Java: Jak porównywać ze sobą zmienne typów wyliczeniowych (enumy)?

Typ wyliczeniowy (enum) jest typem referencyjnym. Oczywistą odpowiedzią, jaka może nasuwać się części osób jest: „Skoro typ referencyjny, to do porównywania będziemy używali metody equals”. I generalnie odpowiedź ta nie jest kompletnie zła, ponieważ faktycznie metoda equals pozwoli nam osiągnąć zamierzony cel.

Lepszą odpowiedzią jest jednak stwierdzenie: Za pomocą operatorów logicznych == oraz !=.

Jaką przewagę ma tutaj zastosowania operatora == nad metodą equals?

  • Użycie metody equals może doprowadzić do rzucenia NullPointerException, a użycie operatora == nie.
  • Przy użyciu operatora == mamy zapewnione sprawdzania zgodności typów już na etapie kompilacji. W przypadku metody equals niestety nie.
Dlaczego jednak nie musimy używać metody equals, skoro enum to typ referencyjny? Charakterystyczną cechą enumów jest to, że istnieje tylko jedna instancja każdej stałej wyliczeniowej. Porównywanie ich adresów w pamięci jest więc wystarczające do określenia czy są sobie równe.

Poniżej przykład, aby lepiej zobrazować wspomniane wyżej zalety takiego podejścia:

enum Role {
    USER,
    ADMIN
}
enum Size {
    S,
    M,
    L,
    XL
}
public static void main(String[] args) {
    Size example = null;
    if (example.equals(Size.S)) {} // zostanie rzucony NPE
    if (example == Size.S) {} // unikamy NPE, porównanie zwraca false

    if (Size.S.equals(Role.ADMIN)) {} // kod kompiluje się bez problemu
    if (Size.S == Role.ADMIN) {} // niezgodność typów, dostajemy błąd już na etapie kompilacji
}

Ktoś mógłby powiedzieć, że w celu uniknięcia NPE, trzeba było w pierwszym przykładzie odwrócić kolejność i zastosować porównanie Size.S.equals(example). Oczywiście jest to prawda, ale nie zmienia ona faktu, że w przypadku porównywania enumów powinniśmy preferować operatory == oraz !=.