Quero verificar se a List
contém um objeto que possui um campo com um determinado valor. Agora, eu poderia usar um loop para passar e verificar, mas fiquei curioso se havia algo mais eficiente em termos de código.
Algo como;
if(list.contains(new Object().setName("John"))){
//Do some stuff
}
Eu sei que o código acima não faz nada, é apenas para demonstrar aproximadamente o que estou tentando alcançar.
Além disso, apenas para esclarecer, a razão pela qual não quero usar um loop simples é porque esse código atualmente está dentro de um loop que está dentro de um loop que está dentro de um loop. Para facilitar a leitura, não quero continuar adicionando loops a esses loops. Então, eu me perguntava se havia alguma alternativa simples (ish).
equals(Object)
método do seu objeto personalizado?for(Person p:list) if (p.getName().equals("John") return true; return false;
Receio que você não encontre uma maneira mais concisa em Java.p.equals(p)
deve ser verdade, então estou confuso com o que você está tentando alcançar. Esperançosamente, se você fizer uma nova pergunta, poderá obter melhor ajuda.Respostas:
Streams
Se você estiver usando o Java 8, talvez você possa tentar algo como isto:
Ou, como alternativa, você pode tentar algo como isto:
Este método irá retornar
true
se oList<MyObject>
contém umaMyObject
com o nomename
. Se você deseja executar uma operação em cada um dosMyObject
s quegetName().equals(name)
, então você pode tentar algo como isto:Onde
o
representa umaMyObject
instância.Como alternativa, como sugerem os comentários (Obrigado MK10), você pode usar o
Stream#anyMatch
método:fonte
public boolean
. Além disso, você pode querer usarObjects.equals()
casoo.getName()
seja possívelnull
.null
verificações, em vez de apenas uma (a minha).return list.stream().anyMatch(o -> o.getName().equals(name));
java.util.Objects
para comparação de segurança nula.return list.stream().anyMatch(o -> Objects.euqals(o.getName(), name);
Se você quiser verificar objetos no fluxo como nulos, poderá adicionar um.filter(Objects::nonNull)
antes de anyMatch.Você tem duas escolhas.
1. A primeira opção, que é preferível, é substituir o método `equals ()` na sua classe Object.
Digamos, por exemplo, você tem esta classe Object:
Agora, digamos que você se preocupa apenas com o nome do MyObject, que deve ser único; portanto, se dois `MyObject`s tiverem o mesmo nome, devem ser considerados iguais. Nesse caso, você deseja substituir o método `equals ()` (e também o método `hashcode ()`) para que ele compare os nomes para determinar a igualdade.
Depois de fazer isso, você pode verificar se uma coleção contém um MyObject com o nome "foo" da seguinte maneira:
No entanto, isso pode não ser uma opção para você se:
Se um desses for o caso, você desejará a opção 2:
2. Escreva seu próprio método utilitário:
Como alternativa, você pode estender o ArrayList (ou alguma outra coleção) e adicionar seu próprio método a ele:
Infelizmente, não há uma maneira melhor de contornar isso.
fonte
Google Guava
Se você estiver usando o Guava , poderá adotar uma abordagem funcional e fazer o seguinte
que parece um pouco detalhado. No entanto, o predicado é um objeto e você pode fornecer variantes diferentes para pesquisas diferentes. Observe como a própria biblioteca separa a iteração da coleção e a função que você deseja aplicar. Você não precisa substituir
equals()
por um comportamento específico.Conforme observado abaixo, a estrutura java.util.Stream integrada ao Java 8 e posterior fornece algo semelhante.
fonte
Iterables.any(list, predicate)
, que é praticamente o mesmo, e você pode ou não preferir estilisticamente.É assim que se faz usando o Java 8+:
fonte
Collection.contains()
é implementado chamandoequals()
cada objeto até que um retornetrue
.Portanto, uma maneira de implementar isso é substituir,
equals()
mas é claro, você pode ter apenas um igual.Estruturas como o Guava, portanto, usam predicados para isso. Com
Iterables.find(list, predicate)
, você pode procurar campos arbitrários colocando o teste no predicado.Outros idiomas criados na parte superior da VM têm isso incorporado. No Groovy , por exemplo, você simplesmente escreve:
O Java 8 também facilitou todas as nossas vidas:
Se você se importa com coisas assim, sugiro o livro "Além do Java". Ele contém muitos exemplos para as inúmeras deficiências do Java e como outras linguagens se saem melhor.
fonte
equals()
é muito limitada. Significa verificar a "identidade do objeto" - o que isso possa significar para alguma classe de objetos. Se você adicionou um sinalizador cujos campos devem ser incluídos, isso pode causar todos os tipos de problemas. Eu recomendo fortemente contra isso.def result = list.find{ it.name == 'John' }
O Oracle / JCP deve ser processado por crimes de guerra contra programadores.Pesquisa binária
Você pode usar o Collections.binarySearch para pesquisar um elemento na sua lista (supondo que a lista esteja classificada):
que retornará um número negativo se o objeto não estiver presente na coleção ou retornará
index
o objeto. Com isso, você pode procurar objetos com diferentes estratégias de pesquisa.fonte
Mapa
Você pode criar um
Hashmap<String, Object>
usando um dos valores como chave e ver seyourHashMap.keySet().contains(yourValue)
retorna verdadeiro.fonte
Coleções Eclipse
Se você estiver usando o Eclipse Collections , poderá usar o
anySatisfy()
método Adapte o seuList
em umListAdapter
ou troque-oList
para um,ListIterable
se possível.Se você realizar operações como essa com frequência, é melhor extrair um método que responda se o tipo tem o atributo
Você pode usar o formulário alternativo
anySatisfyWith()
junto com uma referência de método.Se você não pode transformar seu
List
em umListIterable
, veja como você usariaListAdapter
.Nota: Sou um colaborador das coleções do Eclipse.
fonte
Predicate
Se você não usa o Java 8 ou a biblioteca que oferece mais funcionalidades para lidar com coleções, você pode implementar algo que pode ser mais reutilizável que a sua solução.
Estou usando algo assim, tenho interface de predicado e estou passando a implementação para minha classe util.
Qual é a vantagem de fazer isso no meu caminho? você tem um método que trata da pesquisa em qualquer coleção de tipos. e você não precisa criar métodos separados se quiser pesquisar por campos diferentes. Tudo o que você precisa fazer é fornecer um predicado diferente que possa ser destruído assim que não for mais útil /
se você quiser usá-lo, tudo o que você precisa fazer é chamar o método e definir seu predicado
fonte
Aqui está uma solução usando o Goiaba
fonte
contains
O método usaequals
internamente. Portanto, você precisa substituir oequals
método da sua classe, conforme sua necessidade.Btw isso não parece sintaticamente correto:
fonte
this
.equals
um único caso de uso, a menos que faça sentido para a classe em geral. Você ficaria muito melhor escrevendo o loop.Se você precisar executar isso
List.contains(Object with field value equal to x)
repetidamente, uma solução simples e eficiente seria:Então o resultado
List.contains(Object with field value equal to x)
seria o mesmo quefieldOfInterestValues.contains(x);
fonte
você também pode
anyMatch()
usar:fonte
Apesar do JAVA 8 SDK, existem muitas ferramentas de coleção nas quais as bibliotecas podem ajudá-lo a trabalhar, por exemplo: http://commons.apache.org/proper/commons-collections/
fonte