equals und instanceOf pattern matching

mihe7

Top Contributor
Seit Java 16 gibt es das instanceOf pattern matching, das ich bislang einfach nur als Vereinfachung gesehen habe. Jetzt bin ich allerdings über diverse Inhalte gestoßen, von denen ich einigermaßen begeistert bin und die ich Euch nicht vorenthalten möchte.



Vorher aber kurz eine Erklärung, für diejenigen, die nicht wissen, worum es beim instanceOf pattern matching geht. Manchmal steht man vor dem Problem, dass man ein Objekt bekommt und prüfen muss, ob das Objekt eine Instanz eines bestimmten Typs ist, um anschließend mit den Methoden dieses Typs weiterarbeiten zu können.

Bis Java 15 waren hierfür drei Schritte notwendig.
  1. Prüfen, ob das gegebene Objekt eine Instanz des Typs ist.
  2. Falls ja, das Objekt auf den betreffenden Typ casten und
  3. einer mit diesem Typ deklarierten, lokalen Variablen zuweisen.
In Code:
Java:
if (obj instanceOf Typ) {
    Typ instanz = (Typ) obj;
    // mach was mit instanz
}

Siet Java 16 kann man nun kurz schreiben:
Java:
if (obj instanceof Typ instanz) {
    // mach was mit instanz
}




Zurück zum eigentlichen Thema. Die equals-Methode wird üblicherweise ähnlich überschrieben, wie im folgenden Beispiel gezeigt:
Java:
public boolean equals(Object obj) {
    if (obj == this) return true;
    if (obj == null) return false;
    if (!(obj instanceof Typ)) return false;
    Typ other = (Typ) obj;
    return this.x == other.x
            && this.y == other.y;
}

Mit pattern matching kann man nun z. B. schreiben:
Java:
public boolean equals(Object obj) {
    if (this == obj) return true;
    return (obj instanceof Typ other)
            && this.x == other.x
            && this.y == other.y;
}

In dieser Art hat das Brian Goetz auch für das JDK committed. Klar, das ist kürzer und einfacher zu lesen. Der Knaller aber ist, dass der Spaß auch noch schneller ist (wobei das auch davon abhängt, womit man vergleicht):
Code:
Benchmark       (mode)   Mode  Cnt       Score       Error  Units
Main.benchmark     old  thrpt   30  241058,051 ±  4640,652  ops/s
Main.benchmark     new  thrpt   30  629972,551 ± 11241,051  ops/s
(Edit / Hinweis: hier hat sich leider ein Fehler eingeschlichen - siehe #8 für Details bezüglich der Geschwindigkeit, die ungefähr gleich ist bei beiden Varianten)

Im JEP zum instanceOf pattern matching wird die equals-Methode gar in dieser Weise implementiert:
Java:
public boolean equals(Object obj) {
    return (obj instanceof Typ other)
            && this.x == other.x
            && this.y == other.y;
}

Das gefällt mir! Aber warum wird hier sogar völlig auf die Referenzvergleiche verzichtet? José Paumard hat darauf eine Antwort: predictive branching.

Die CPU macht Vorhersagen, welcher Zweig durchlaufen werden wird und kann so die Pipeline besser füllen. Stellt sich heraus, dass die Vorhersage falsch war (der Referenzvergleich muss ja in jedem Fall ausgeführt werden), muss zurückgesetzt werden - was im Verhältnis massig Zeit kostet. In Summe macht dies den Versuch der Optimierung über den Referenzvergleich oft zunichte.
 
Zuletzt bearbeitet von einem Moderator:

LimDul

Top Contributor
Im JEP zum instanceOf pattern matching wird die equals-Methode gar in dieser Weise implementiert:
Java:
public boolean equals(Object obj) {
    return (obj instanceof Typ other)
            && this.x == other.x 
            && this.y == other.y;
}

Das gefällt mir! Aber warum wird hier sogar völlig auf die Referenzvergleiche verzichtet? José Paumard hat darauf eine Antwort: predictive branching.

Die CPU macht Vorhersagen, welcher Zweig durchlaufen werden wird und kann so die Pipeline besser füllen. Stellt sich heraus, dass die Vorhersage falsch war (der Referenzvergleich muss ja in jedem Fall ausgeführt werden), muss zurückgesetzt werden - was im Verhältnis massig Zeit kostet. In Summe macht dies den Versuch der Optimierung über den Referenzvergleich oft zunichte.
Das find ich interessant - und es ist ein Klasse Beispiel, warum Mikro-Optimierungen selten sinnvoll sind. Das der Code ohne Referenzvergleich schneller ist, ist nicht offensichtlich - zeigt aber, dass bei den ganzen Mechanismen die passieren, bis wirklich Code auf der CPU ausgeführt wird, bereits so viel "Magie" drin ist, dass man mit Mikro-Optimierungen leicht das Gegenteil erreicht. Bzw. man solche Sachen wirklich genau messen muss. (Und selbst dann ist nicht klar, ob das bei der nächsten CPU-Generation, nächsten Java-Version etc. immer noch gilt)
 

httpdigest

Top Contributor
Interessant ist tatsächlich der Unterschied zwischen:
Java:
public boolean equals(Object obj) {
if (!(obj instanceof A)) return false;
    A other = (A) obj;
    return this.x == other.x
            && this.y == other.y;
}
mit:
Code:
 0: aload_1
 1: instanceof    #7
 4: ifne          9
 7: iconst_0
 8: ireturn
 9: aload_1
10: checkcast     #7
13: astore_2
14: aload_0
15: getfield      #9
18: aload_2
19: getfield      #9
22: if_icmpne     40
25: aload_0
26: getfield      #13
29: aload_2
30: getfield      #13
33: if_icmpne     40
36: iconst_1
37: goto          41
40: iconst_0
41: ireturn
und:
Java:
public boolean equals(Object obj) {
  return (obj instanceof B other)
            && this.x == other.x
            && this.y == other.y;
}
mit:
Code:
 0: aload_1
 1: instanceof    #7
 4: ifeq          38 <---- Unterschied hier!
 7: aload_1
 8: checkcast     #7
11: astore_2
12: aload_0
13: getfield      #9
16: aload_2
17: getfield      #9
20: if_icmpne     38
23: aload_0
24: getfield      #13
27: aload_2
28: getfield      #13
31: if_icmpne     38
34: iconst_1
35: goto          39
38: iconst_0
39: ireturn
Macht "scheinbar" exakt dasselbe, also selbe Anzahl von instanceof Aufrufen und checkcast Aufrufen.
Nur, der Vergleich beim instanceof ist umgedreht. Im A-Fall (traditionell) wird im "true"-Fall ein klein bisschen weiter gesprungen und im "false"-Fall nicht gesprungen.
Im B-Fall (instanceof pattern matching) wird im "true"-Fall nicht gesprungen, und im "false"-Fall sehr weit gesprungen.
Beide Fälle haben (zumindest im JVM Bytecode) exakt gleich viele Vergleiche, instanceof und checkcasts.

Prinzipiell würde ich sagen, ist das "instanceof Pattern Matching" nur syntaktischer Zucker, der aber zu leicht anderen bedingten Sprüngen im generierten JVM Bytecode führt. Also, "HotSpot" wird beim Laden der .class Datei bzw. der Methodendefinition nicht mehr wissen, ob das nun aus einem "instanceof Pattern Matching" kam, oder dieser JVM Bytecode anderweitig generiert wurde. Eine Verbesserung scheint es aber ja dennoch zu sein. :)
 
Zuletzt bearbeitet:

mihe7

Top Contributor
Na, wenn du schon mit so einem generell interessanten Thema kommst, dann war das doch das Naheliegendste, oder nicht? :D
Eigentlich schon, aber das hatte ich jetzt gar nicht auf dem Schirm. Ich habe JMH bemüht und wenn ich mir den Bytecode ansehe, dann frage ich mich allerdings auch, wo der Unterschied herkommt.

Für den Fall, dass es jemanden interessiert:

 

httpdigest

Top Contributor
Dann wäre ja dein JMH Setup eigentlich der interessante Part. :)
Bei mir kam nicht wirklich ein Unterschied zwischen den beiden Versionen heraus.
 

mihe7

Top Contributor
Erstmal Dank an @httpdigest, der den Spaß nochmal überprüft hat. Dann bitte ich um Asche auf mein Haupt: da sitzt man den halben Tag vor dem Code und übersieht die ganze Zeit einen besch... Copy & Paste Fehler (bei der Implementierung mit pattern matching per instanceOf auf die andere Klasse getestet, womit der eigentlich Vergleich nie ausgeführt wurde).

Jetzt sehen die Zahlen gleich ganz anders aus, z. B.
Code:
Benchmark       (mode)   Mode  Cnt       Score       Error  Units
Main.benchmark     old  thrpt   30  221621,799 ± 5688,223  ops/s
Main.benchmark     new  thrpt   30  224580,516 ± 4933,007  ops/s
Also praktisch kein Unterschied.

Der Knaller aber ist, dass der Spaß auch noch schneller ist (wobei das auch davon abhängt, womit man vergleicht):
Das ist somit schlichtweg falsch. @KonradN kannst Du in den Beitrag einen entsprechenden Hinweis aufnehmen, ggf. mit Link auf diesen Kommentar?
 

Ullenboom

Bekanntes Mitglied
Kleine Randbemerkung: Man sollte sich gut überlegen, ob man instanceof nutzen oder Class-Objekte vergleichen möchte. Mit Class-Objekten hat man kein Problem der Symmetrie. "Leider" kann man bei other.getClass() == Me.class aber dann nicht mehr die schönen Pattern-Variablen verwenden.
 

mihe7

Top Contributor
Das ist natürlich richtig, wobei die Symmetrie sowieso hinüber ist, wenn z. B. Proxies im Spiel sind. Da funktionieren die Vergleiche der Class-Objekte natürlich auch nicht mehr.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
P Strings: equals vs == Allgemeine Java-Themen 47
F Methoden hashCode() & equals() Allgemeine Java-Themen 13
J Equals Mock Objekte Allgemeine Java-Themen 5
J Mockito - Objekte miteinander vergleichen (equals) Allgemeine Java-Themen 6
J Probleme mit CodeCoverage und Lombok Equals Allgemeine Java-Themen 1
S equals-Methode bestimmer Klassen abfangen Allgemeine Java-Themen 2
T Zwei Wortendungen vergleichen ohne .equals Allgemeine Java-Themen 10
C Object.equals() liefert falschen Wert? Allgemeine Java-Themen 14
T Collections TreeSet.contains ruft nicht .equals? Allgemeine Java-Themen 4
H Problem mit der .equals()-Methode Allgemeine Java-Themen 2
T Compiler-Fehler not equals Allgemeine Java-Themen 22
I HashMap key wird nicht erkannt trotz überschriebener equals/hashCode Methode Allgemeine Java-Themen 6
V ArrayList vergleichen mit .equals? Allgemeine Java-Themen 13
A mit .equals Array befüllen schlägt teilweise fehl Allgemeine Java-Themen 3
G Probleme mit equals Allgemeine Java-Themen 3
R Merkwürdiges Verhalten der equals Method Allgemeine Java-Themen 4
tuttle64 equals() und == Allgemeine Java-Themen 4
B Probleme mit eigener equals Methode Allgemeine Java-Themen 18
H double dispatch und equals(Object) Allgemeine Java-Themen 6
S equals - Identität ändern bei Vererbung? Allgemeine Java-Themen 5
fastjack jUnit und Test von equals, hashCode, toString Allgemeine Java-Themen 11
K Collection.contains()/retainAll() mit Referenzgleichheit statt equals()? Allgemeine Java-Themen 2
J Best Practice für implementierung von equals(...) Allgemeine Java-Themen 7
M equals & compareTo Allgemeine Java-Themen 15
M Warum Strings mit equals vergleichen... Allgemeine Java-Themen 6
T Wie intelligent ist dieses überschriebene .equals() ? Allgemeine Java-Themen 13
G Objektvergleich mit equals Allgemeine Java-Themen 5
vogella Überschreiben von equals und hashcode für Collection Allgemeine Java-Themen 7
M String#equals(), Probleme mit großen Strings? Allgemeine Java-Themen 4
André Uhres equals überschreiben Allgemeine Java-Themen 31
F Problem: mehrere Interfaces definieren equals() neu Allgemeine Java-Themen 24
A equals() macht nicht, was es soll Allgemeine Java-Themen 4
B Equals Methode überschreiben mit Array Allgemeine Java-Themen 2
M equals() != compareTo() ? Allgemeine Java-Themen 3
M String mit equals() vergleichen - Frage Allgemeine Java-Themen 3
S equals überladen Allgemeine Java-Themen 15
S Mal was allgemeines zu equals() Allgemeine Java-Themen 12
J Arrays vergleichen mit equals Allgemeine Java-Themen 8
M instanceof bei generischer Methode Allgemeine Java-Themen 3
E instanceof mit nicht öffentlichen Klassen Allgemeine Java-Themen 2
D instanceof oder was anderes? Allgemeine Java-Themen 12
J instanceof vermeiden und stattdessen dynamisch binden Allgemeine Java-Themen 6
M Vermeiden von instanceof Abfragen Allgemeine Java-Themen 3
S Kompositum Muster ohne Exception oder instanceof Operator Allgemeine Java-Themen 6
S instanceof liefert true, aber cast funktioniert nicht! Allgemeine Java-Themen 6
P instanceof mit variabler klasse Allgemeine Java-Themen 3
G Probleme mit ÜbergabeParameter für instanceof Allgemeine Java-Themen 3
T Klasse => Primitiv ? Object instanceof Klasse Allgemeine Java-Themen 2
T Generics und instanceof Allgemeine Java-Themen 10
M Ersatz fuer instanceof Allgemeine Java-Themen 11
Y instanceof unschön ! Allgemeine Java-Themen 6
J instanceof vermeiden Allgemeine Java-Themen 10
S instanceof und null Allgemeine Java-Themen 7
S instanceof mit genrics Allgemeine Java-Themen 3
L Pattern Eventhandler Allgemeine Java-Themen 5
EinNickname9 Best Practice Singleton und Singleton mit Instanz zu anderer Klasse -Pattern Allgemeine Java-Themen 30
Z MVC Pattern - sinnvolle Integration Allgemeine Java-Themen 6
J Meinung zum verwendeten Design Pattern Allgemeine Java-Themen 4
Kirby.exe Filename nach bestimmtem Pattern durchsuchen Allgemeine Java-Themen 5
Meeresgott Best Practice "Spezifisches" Factory Pattern ? Allgemeine Java-Themen 1
H Strategy Pattern - changeColor() Methode - input rgd oder hex einlesen Allgemeine Java-Themen 1
M Vaadin MVP Pattern Allgemeine Java-Themen 1
N Java MVC Pattern richtig anwenden Allgemeine Java-Themen 24
M OOP Design Pattern - "extends Observable implements Observer" Allgemeine Java-Themen 0
K Factory Pattern: Mit Generics umgehen Allgemeine Java-Themen 6
perlenfischer1984 Welches Design Pattern ist geegneit. Allgemeine Java-Themen 7
perlenfischer1984 Hilfe bei Design (Pattern) Allgemeine Java-Themen 5
J Compilerfehler bis in java.util.regex.Pattern... Allgemeine Java-Themen 2
B MVC-Pattern größeres Beispiel Allgemeine Java-Themen 16
GreenTeaYT Verstehe nicht ganz das Observer Pattern in einer Arrayliste? Allgemeine Java-Themen 3
L Erste Schritte Java Date Format Pattern bestimmten Allgemeine Java-Themen 2
D Pattern mit Pattern vergleichen Allgemeine Java-Themen 3
D OOP Design Pattern für GUI - Datenbank Anwendung Allgemeine Java-Themen 1
S Hilfe bei geeignetem Pattern (Decorierer) Allgemeine Java-Themen 2
F Welches Design Pattern? Allgemeine Java-Themen 3
J Pattern aus String entfernen Allgemeine Java-Themen 2
S Pattern.Match Suche: For Schleife einbinden und in Liste schreiben Allgemeine Java-Themen 3
D Variablen zur Laufzeit global speichern (Registry Pattern?) Allgemeine Java-Themen 6
Rudolf State Pattern als Enum? Allgemeine Java-Themen 10
M massenhaft verschiedene Date-Pattern Allgemeine Java-Themen 3
Guybrush Threepwood Pattern gesucht: Punkt ohne Leerzeichen dahinter Allgemeine Java-Themen 3
turmaline OOP Decorater Pattern für Varifikationsverhalten Allgemeine Java-Themen 13
T HTML Tag Position mittels Pattern ermitteln Allgemeine Java-Themen 7
X Datentypen Prozentualer Abgleich zwischen 2 Strings (Pattern?) Allgemeine Java-Themen 3
H Pattern.compile Syntax Allgemeine Java-Themen 15
B RegEx: (Um-)formulieren eines Pattern zur Identifizierung komplexer URLs Allgemeine Java-Themen 7
D [Drag&Drop] Design-Pattern-Frage Allgemeine Java-Themen 4
T Pattern für Benutzer-Gruppen, RMI Allgemeine Java-Themen 5
E Super erzwingen, konzept/pattern gesucht. Allgemeine Java-Themen 8
H Problem mit der Klasse Pattern - Regulärer Ausdruck Allgemeine Java-Themen 2
Eldorado Meinung zu einem abgewandelten MVC-Pattern Allgemeine Java-Themen 2
R Matcher - Pattern mit belibigem Anfang Allgemeine Java-Themen 2
H Bestimmten String mit Pattern und Matcher herauslesen => kein erfolg Allgemeine Java-Themen 9
I Pattern zum Erweitern existierender Objekte Allgemeine Java-Themen 4
I Template Method pattern mit "geschützten Methoden" Allgemeine Java-Themen 5
T Pattern: Passive View Allgemeine Java-Themen 2
K Verständnisprobleme bei Observer-Pattern mit größerem Datenmodell Allgemeine Java-Themen 32
T Pattern: Greedy, Reluctant, Possessive Allgemeine Java-Themen 4
S Hilfe bei Pattern Allgemeine Java-Themen 5
N Registry Pattern Allgemeine Java-Themen 7

Ähnliche Java Themen

Neue Themen


Oben