tl; dr moim zdaniem jest użycie jedności +do uruchomienia rozpakowywania na jednym z operandów podczas sprawdzania równości wartości, a po prostu użycie operatorów matematycznych w przeciwnym razie. Uzasadnienie jest następujące:
Wspomniano już, że ==porównanie Integerto porównanie tożsamości, które zwykle nie jest tym, czego chce programista, a celem jest porównanie wartości; Mimo to zrobiłem trochę nauki o tym, jak zrobić to porównanie najbardziej wydajnie, zarówno pod względem zwięzłości kodu, poprawności i szybkości.
Użyłem zwykłej wiązki metod:
public boolean method1() {
Integer i1 = 7, i2 = 5;
return i1.equals( i2 );
}
public boolean method2() {
Integer i1 = 7, i2 = 5;
return i1.intValue() == i2.intValue();
}
public boolean method3() {
Integer i1 = 7, i2 = 5;
return i1.intValue() == i2;
}
public boolean method4() {
Integer i1 = 7, i2 = 5;
return i1 == +i2;
}
public boolean method5() { // obviously not what we want..
Integer i1 = 7, i2 = 5;
return i1 == i2;
}
i otrzymałem ten kod po kompilacji i dekompilacji:
public boolean method1() {
Integer var1 = Integer.valueOf( 7 );
Integer var2 = Integer.valueOf( 5 );
return var1.equals( var2 );
}
public boolean method2() {
Integer var1 = Integer.valueOf( 7 );
Integer var2 = Integer.valueOf( 5 );
if ( var2.intValue() == var1.intValue() ) {
return true;
} else {
return false;
}
}
public boolean method3() {
Integer var1 = Integer.valueOf( 7 );
Integer var2 = Integer.valueOf( 5 );
if ( var2.intValue() == var1.intValue() ) {
return true;
} else {
return false;
}
}
public boolean method4() {
Integer var1 = Integer.valueOf( 7 );
Integer var2 = Integer.valueOf( 5 );
if ( var2.intValue() == var1.intValue() ) {
return true;
} else {
return false;
}
}
public boolean method5() {
Integer var1 = Integer.valueOf( 7 );
Integer var2 = Integer.valueOf( 5 );
if ( var2 == var1 ) {
return true;
} else {
return false;
}
}
Jak łatwo zauważyć, wywołania metody 1 Integer.equals()(oczywiście), metody 2-4 dają dokładnie ten sam kod , rozpakowywanie wartości za pomocą, .intValue()a następnie bezpośrednie porównywanie, a metoda 5 po prostu uruchamia porównanie tożsamości, ponieważ jest to niewłaściwy sposób porównaj wartości.
Ponieważ (jak już wspomniano np. JS) equals()powoduje narzut (musi to zrobić instanceofi niezaznaczone rzutowanie), metody 2-4 będą działały z dokładnie taką samą prędkością, zauważalnie lepszą niż metoda 1, gdy są używane w ciasnych pętlach, ponieważ HotSpot nie jest prawdopodobnie zoptymalizuje obsady i instanceof.
Jest całkiem podobny do innych operatorów porównania (np. </ >) - będą wyzwalać rozpakowywanie, podczas gdy używanie compareTo()tego nie zrobi - ale tym razem operacja jest wysoce zoptymalizowana przez HS, ponieważ intValue()jest to tylko metoda gettera (główna kandydatka do optymalizacji).
Moim zdaniem, rzadko stosowany w wersji 4 jest najbardziej zwięzły sposób - każdy zaprawiony programista C / Java wie, że jednoargumentowy plus to w większości przypadków równa do obsady do int/ .intValue()- choć może to być trochę WTF moment dla niektórych (głównie tych, którzy didn nie używają jednoznacznego plusa w ciągu swojego życia), najprawdopodobniej pokazuje intencję najdokładniej i najdokładniej - pokazuje, że chcemy intwartości jednego z argumentów, zmuszając również drugą wartość do rozpakowania. Jest również bezsprzecznie najbardziej podobny do zwykłego i1 == i2porównania stosowanego dla pierwotnych intwartości.
Mój głos dotyczy stylu i1 == +i2i obiektów, zarówno ze względu na wydajność, jak i spójność. Dzięki temu kod jest przenośny dla prymitywów, nie zmieniając niczego poza deklaracją typu. Używanie nazwanych metod wydaje mi się wprowadzać do mnie hałas semantyczny, podobny do bardzo krytykowanego stylu.i1 > i2IntegerbigInt.add(10).multiply(-3)