Chcę sprawdzić, czy List
zawiera obiekt, który ma pole o określonej wartości. Teraz mogłem użyć pętli, aby przejść i sprawdzić, ale byłem ciekawy, czy jest coś bardziej wydajnego w kodzie.
Coś jak;
if(list.contains(new Object().setName("John"))){
//Do some stuff
}
Wiem, że powyższy kod nic nie robi, to tylko przybliżenie tego, co próbuję osiągnąć.
Ponadto, aby wyjaśnić, powodem, dla którego nie chcę używać prostej pętli, jest to, że ten kod będzie teraz wchodził w pętlę, która znajduje się w pętli, która jest w pętli. Dla czytelności nie chcę ciągle dodawać pętli do tych pętli. Zastanawiałem się więc, czy istnieją jakieś proste (ish) alternatywy.
equals(Object)
metodę swojego obiektu niestandardowego?for(Person p:list) if (p.getName().equals("John") return true; return false;
Obawiam się, że nie znajdziesz bardziej zwięzłego sposobu w Javie.p.equals(p)
powinno zawsze być prawdą, więc nie rozumiem, co próbujesz osiągnąć. Mam nadzieję, że jeśli zadajesz nowe pytanie , możesz uzyskać lepszą pomoc.Odpowiedzi:
Strumienie
Jeśli używasz Java 8, być może możesz spróbować czegoś takiego:
Możesz też spróbować czegoś takiego:
Ta metoda zwróci,
true
jeśliList<MyObject>
zawiera onaMyObject
z nazwąname
. Jeśli chcesz wykonać operację na każdymMyObject
z którągetName().equals(name)
, to można spróbować czegoś takiego:Gdzie
o
reprezentujeMyObject
instancję.Alternatywnie, jak sugerują komentarze (Dzięki MK10), możesz użyć
Stream#anyMatch
metody:źródło
public boolean
. Ponadto, warto użyćObjects.equals()
w przypadkuo.getName()
może byćnull
.null
kontroli, a nie tylko jedną (moją).return list.stream().anyMatch(o -> o.getName().equals(name));
java.util.Objects
do porównania nullsafereturn list.stream().anyMatch(o -> Objects.euqals(o.getName(), name);
Jeśli chcesz sprawdzić obiekty w strumieniu pod kątem null, możesz dodać znak.filter(Objects::nonNull)
przed anyMatch.Masz dwie możliwości.
1. Pierwszym wyborem, który jest lepszy, jest zastąpienie metody `equals ()` w klasie Object.
Załóżmy na przykład, że masz tę klasę Object:
Powiedzmy teraz, że zależy ci tylko na nazwie MyObject, aby była unikalna, więc jeśli dwa `MyObject`s mają taką samą nazwę, powinny być uważane za równe. W takim przypadku należy zastąpić metodę `equals ()` (a także metodę `hashcode ()`), aby porównała nazwy w celu ustalenia równości.
Po wykonaniu tej czynności możesz sprawdzić, czy kolekcja zawiera obiekt MyObject o nazwie „foo”, w ten sposób:
Jednak może to nie być dla Ciebie opcja, jeśli:
Jeśli tak jest w obu przypadkach, będziesz potrzebować opcji 2:
2. Napisz własną metodę użyteczności:
Alternatywnie możesz rozszerzyć ArrayList (lub inną kolekcję), a następnie dodać do niej własną metodę:
Niestety nie ma lepszego sposobu na obejście tego.
źródło
Google Guava
Jeśli używasz Guawy , możesz zastosować funkcjonalne podejście i wykonać następujące czynności
co wygląda na trochę gadatliwe. Jednak predykat jest obiektem i możesz podać różne warianty dla różnych wyszukiwań. Zwróć uwagę, jak sama biblioteka oddziela iterację kolekcji i funkcję, którą chcesz zastosować. Nie musisz przesłonić
equals()
określonego zachowania.Jak zauważono poniżej, framework java.util.Stream wbudowany w Javę 8 i później zapewnia coś podobnego.
źródło
Iterables.any(list, predicate)
, który jest praktycznie taki sam, i możesz preferować stylistycznie.Oto jak to zrobić za pomocą Java 8+:
źródło
Collection.contains()
jest implementowany przez wywołanieequals()
każdego obiektu, dopóki jeden nie powrócitrue
.Tak więc jednym ze sposobów na wdrożenie tego jest zastąpienie,
equals()
ale oczywiście można mieć tylko jeden równy.Dlatego też struktury takie jak Guava używają do tego predykatów. Z
Iterables.find(list, predicate)
można wyszukiwać dowolne pola, umieszczając test w predykacie.Inne języki zbudowane na maszynie wirtualnej mają tę wbudowaną funkcję. Na przykład w Groovy po prostu piszesz:
Java 8 także ułatwiła nam życie:
Jeśli zależy Ci na takich rzeczach, sugeruję książkę „Beyond Java”. Zawiera wiele przykładów licznych wad Java i lepszego radzenia sobie z innymi językami.
źródło
equals()
jest bardzo ograniczony. Oznacza to sprawdzenie „tożsamości obiektu” - cokolwiek to może oznaczać dla niektórych klas obiektów. Jeśli dodasz flagę, które pola powinny zostać uwzględnione, może to powodować różnego rodzaju problemy. Zdecydowanie odradzam to.def result = list.find{ it.name == 'John' }
Oracle / JCP powinny być pozwane za zbrodnie wojenne przeciwko programistom.Wyszukiwanie binarne
Możesz użyć Collections.binarySearch, aby wyszukać element na liście (zakładając, że lista jest posortowana):
który zwróci liczbę ujemną, jeśli obiekt nie będzie obecny w kolekcji, lub zwróci
index
obiekt. Dzięki temu możesz wyszukiwać obiekty o różnych strategiach wyszukiwania.źródło
Mapa
Możesz utworzyć
Hashmap<String, Object>
jedną z wartości jako klucz, a następnie sprawdzić, czyyourHashMap.keySet().contains(yourValue)
zwraca true.źródło
Kolekcje Eclipse
Jeśli korzystasz z kolekcji Eclipse , możesz użyć tej
anySatisfy()
metody. Dostosuj swójList
wListAdapter
lub zmieńList
w na,ListIterable
jeśli to możliwe.Jeśli często będziesz wykonywać takie operacje, lepiej wyodrębnić metodę, która odpowiada, czy typ ma atrybut.
Możesz użyć alternatywnego formularza
anySatisfyWith()
wraz z odwołaniem do metody.Jeśli nie możesz zmienić swojego
List
naListIterable
, oto sposób, w jaki chcesz go użyćListAdapter
.Uwaga: jestem zleceniodawcą kolekcji Eclipse.
źródło
Predicate
Jeśli nie używasz Java 8 lub biblioteki, która daje więcej funkcji do obsługi kolekcji, możesz zaimplementować coś, co może być bardziej przydatne niż twoje rozwiązanie.
używam czegoś takiego, mam interfejs predykatu i przekazuję jego implementację do mojej klasy util.
Jaka jest zaleta robienia tego na mój sposób? masz jedną metodę, która zajmuje się wyszukiwaniem w kolekcji dowolnego typu. i nie musisz tworzyć osobnych metod, jeśli chcesz wyszukiwać według innego pola. wszystko, co musisz zrobić, to podać inny predykat, który może zostać zniszczony, gdy tylko przestanie być przydatny /
jeśli chcesz go użyć, wszystko, co musisz zrobić, to wywołać metodę i zdefiniować predykat
źródło
Oto rozwiązanie wykorzystujące Guava
źródło
contains
metoda wykorzystujeequals
wewnętrznie. Musisz więc zastąpićequals
metodę dla swojej klasy zgodnie z potrzebami.Przy okazji nie wygląda to na poprawną składniowo:
źródło
this
.equals
dla pojedynczego przypadku użycia, chyba że ma to sens dla klasy w ogóle. Lepiej byłoby po prostu napisać pętlę.Jeśli musisz to
List.contains(Object with field value equal to x)
powtarzać wielokrotnie, prostym i wydajnym obejściem byłoby:Wówczas
List.contains(Object with field value equal to x)
otrzymalibyśmy taki sam wynik jakfieldOfInterestValues.contains(x);
źródło
możesz również
anyMatch()
użyć:źródło
Pomimo JAVA 8 SDK istnieje wiele bibliotek narzędzi do zbierania, które mogą pomóc w pracy, na przykład: http://commons.apache.org/proper/commons-collections/
źródło