Ich möchte überprüfen, ob a List
ein Objekt enthält, das ein Feld mit einem bestimmten Wert hat. Jetzt könnte ich eine Schleife verwenden, um zu überprüfen, aber ich war neugierig, ob es etwas Code-effizienteres gibt.
Etwas wie;
if(list.contains(new Object().setName("John"))){
//Do some stuff
}
Ich weiß, dass der obige Code nichts bewirkt, sondern nur grob demonstriert, was ich erreichen möchte.
Zur Verdeutlichung möchte ich keine einfache Schleife verwenden, da dieser Code derzeit in eine Schleife innerhalb einer Schleife innerhalb einer Schleife eingefügt wird. Aus Gründen der Lesbarkeit möchte ich diesen Schleifen nicht ständig Schleifen hinzufügen. Also fragte ich mich, ob es einfache (ish) Alternativen gab.
equals(Object)
Methode Ihres benutzerdefinierten Objekts überschreiben ?for(Person p:list) if (p.getName().equals("John") return true; return false;
Ich fürchte, Sie werden in Java keinen prägnanteren Weg finden.p.equals(p)
sollte immer wahr sein, also bin ich verwirrt, was Sie erreichen wollen. Wenn Sie eine neue Frage stellen , können Sie hoffentlich bessere Hilfe erhalten.Antworten:
Streams
Wenn Sie Java 8 verwenden, können Sie vielleicht Folgendes ausprobieren:
Alternativ können Sie auch Folgendes ausprobieren:
Diese Methode wird zurückgegeben,
true
wenn sieList<MyObject>
einMyObject
mit dem Namen enthältname
. Wenn Sie eine Operation für jedes derMyObject
s ausführen möchtengetName().equals(name)
, können Sie Folgendes versuchen:Wo
o
repräsentiert eineMyObject
Instanz.Alternativ können Sie, wie aus den Kommentaren hervorgeht (Danke MK10), die folgende
Stream#anyMatch
Methode verwenden:quelle
public boolean
. Vielleicht möchten Sie auch verwenden,Objects.equals()
fallso.getName()
dies möglich istnull
.null
Überprüfungen durchführen, im Gegensatz zu nur einer (meiner).return list.stream().anyMatch(o -> o.getName().equals(name));
java.util.Objects
für einen nullsicheren Vergleich verwenden.return list.stream().anyMatch(o -> Objects.euqals(o.getName(), name);
Wenn Sie Objekte im Stream auf null prüfen möchten, können Sie.filter(Objects::nonNull)
vor anyMatch ein hinzufügen.Sie haben zwei Möglichkeiten.
1. Die erste Wahl, die vorzuziehen ist, besteht darin, die Methode `equals ()` in Ihrer Object-Klasse zu überschreiben.
Angenommen, Sie haben diese Objektklasse:
Angenommen, Sie interessieren sich nur für den Namen des MyObjects, der eindeutig sein sollte. Wenn also zwei MyObjects denselben Namen haben, sollten sie als gleich angesehen werden. In diesem Fall möchten Sie die Methode `equals ()` (und auch die Methode `hashcode ()` überschreiben, damit die Namen verglichen werden, um die Gleichheit zu bestimmen.
Sobald Sie dies getan haben, können Sie überprüfen, ob eine Sammlung ein MyObject mit dem Namen "foo" enthält.
Dies ist jedoch möglicherweise keine Option für Sie, wenn:
Wenn einer dieser Fälle der Fall ist, möchten Sie Option 2:
2. Schreiben Sie Ihre eigene Dienstprogrammmethode:
Alternativ können Sie ArrayList (oder eine andere Sammlung) erweitern und dann Ihre eigene Methode hinzufügen:
Leider gibt es keinen besseren Weg, um es zu umgehen.
quelle
Google Guava
Wenn Sie Guava verwenden , können Sie einen funktionalen Ansatz wählen und Folgendes tun
das sieht ein wenig wortreich aus. Das Prädikat ist jedoch ein Objekt und Sie können verschiedene Varianten für verschiedene Suchvorgänge bereitstellen. Beachten Sie, wie die Bibliothek selbst die Iteration der Sammlung und die Funktion, die Sie anwenden möchten, trennt. Sie müssen
equals()
für ein bestimmtes Verhalten nicht überschreiben .Wie unten erwähnt, bietet das in Java 8 und höher integrierte Framework java.util.Stream etwas Ähnliches.
quelle
Iterables.any(list, predicate)
, was praktisch das gleiche ist, und Sie können es stilistisch bevorzugen oder nicht.So geht's mit Java 8+:
quelle
Collection.contains()
wird implementiert, indemequals()
jedes Objekt aufgerufen wird, bis eines zurückkehrttrue
.Eine Möglichkeit, dies zu implementieren, besteht darin, zu überschreiben,
equals()
aber natürlich können Sie nur eine Gleichheit haben.Frameworks wie Guava verwenden daher Prädikate. Mit
Iterables.find(list, predicate)
können Sie nach beliebigen Feldern suchen, indem Sie den Test in das Prädikat einfügen.In anderen Sprachen, die auf der VM erstellt wurden, ist dies integriert. In Groovy schreiben Sie beispielsweise einfach:
Java 8 hat uns auch das Leben leichter gemacht:
Wenn Sie sich für solche Dinge interessieren, empfehle ich das Buch "Beyond Java". Es enthält viele Beispiele für die zahlreichen Mängel von Java und wie andere Sprachen besser abschneiden.
quelle
equals()
ist sehr begrenzt. Es bedeutet, nach "Objektidentität" zu suchen - was auch immer das für eine Klasse von Objekten bedeuten mag. Wenn Sie ein Flag hinzugefügt haben, welche Felder enthalten sein sollen, kann dies zu Problemen aller Art führen. Ich rate dringend davon ab.def result = list.find{ it.name == 'John' }
Oracle / JCP sollte wegen Kriegsverbrechen gegen Programmierer verklagt werden.Binäre Suche
Mit Collections.binarySearch können Sie ein Element in Ihrer Liste durchsuchen (vorausgesetzt, die Liste ist sortiert):
Dies gibt eine negative Zahl zurück, wenn das Objekt nicht in der Sammlung vorhanden ist, oder es gibt die
index
des Objekts zurück. Damit können Sie nach Objekten mit unterschiedlichen Suchstrategien suchen.quelle
Karte
Sie können einen
Hashmap<String, Object>
mit einem der Werte als Schlüssel erstellen und dann prüfen, obyourHashMap.keySet().contains(yourValue)
true zurückgegeben wird.quelle
Eclipse-Sammlungen
Wenn Sie Eclipse-Sammlungen verwenden , können Sie die
anySatisfy()
Methode verwenden. Passen Sie IhreList
in a anListAdapter
oder ändern Sie IhreList
in eine,ListIterable
wenn möglich.Wenn Sie solche Vorgänge häufig ausführen, ist es besser, eine Methode zu extrahieren, die antwortet, ob der Typ das Attribut hat.
Sie können das alternative Formular
anySatisfyWith()
zusammen mit einer Methodenreferenz verwenden.Wenn Sie Ihre nicht
List
in eine ändern könnenListIterable
, gehen Sie wie folgt vorListAdapter
.Hinweis: Ich bin ein Committer für Eclipse-Sammlungen.
quelle
Predicate
Wenn Sie kein Java 8 oder keine Bibliothek verwenden, die Ihnen mehr Funktionen für den Umgang mit Sammlungen bietet, können Sie etwas implementieren, das wiederverwendbarer ist als Ihre Lösung.
Ich benutze so etwas, ich habe eine Prädikatschnittstelle und ich übergebe die Implementierung an meine util-Klasse.
Was ist der Vorteil, wenn ich das auf meine Weise mache? Sie haben eine Methode, die sich mit der Suche in einer beliebigen Typensammlung befasst. und Sie müssen keine separaten Methoden erstellen, wenn Sie nach verschiedenen Feldern suchen möchten. Alles, was Sie tun müssen, ist, ein anderes Prädikat bereitzustellen, das zerstört werden kann, sobald es nicht mehr nützlich ist.
Wenn Sie es verwenden möchten, müssen Sie lediglich die Methode aufrufen und Ihr Prädikat definieren
quelle
Hier ist eine Lösung mit Guava
quelle
contains
Methode verwendetequals
intern. Sie müssen also dieequals
Methode für Ihre Klasse gemäß Ihren Anforderungen überschreiben .Übrigens sieht das syntaktisch nicht korrekt aus:
quelle
this
.equals
für einen einzelnen Anwendungsfall zu überschreiben , es sei denn, dies ist für die Klasse im Allgemeinen sinnvoll. Sie wären viel besser dran, wenn Sie nur die Schleife schreiben würden.Wenn Sie dies
List.contains(Object with field value equal to x)
wiederholt ausführen müssen , wäre eine einfache und effiziente Problemumgehung:Dann
List.contains(Object with field value equal to x)
hätte das das gleiche Ergebnis wiefieldOfInterestValues.contains(x);
quelle
Sie können auch
anyMatch()
verwenden:quelle
Trotz des JAVA 8 SDK gibt es viele Sammlungstools, mit denen Bibliotheken arbeiten können, zum Beispiel: http://commons.apache.org/proper/commons-collections/
quelle