Ciekawi mnie, co ludzie tutaj myślą o używaniu
org.apache.commons.lang.builder
EqualsBuilder
/ HashCodeBuilder
do implementacji equals
/ hashCode
? Czy byłaby to lepsza praktyka niż pisanie własnej? Czy dobrze współpracuje z Hibernate? Jakie jest Twoje zdanie?
155
reflectionEquals
ireflectionHashcode
; występ jest absolutnym zabójcą.Odpowiedzi:
Konstruktory Common / Lang są świetne i używam ich od lat bez zauważalnego narzutu wydajności (zi bez hibernacji). Ale jak pisze Alain, droga Guava jest jeszcze przyjemniejsza:
Oto przykładowy Bean:
Oto equals () i hashCode () zaimplementowane za pomocą Commons / Lang:
a tutaj z Javą 7 lub nowszą (inspirowaną Guavą):
Uwaga: ten kod pierwotnie odwoływał się do guawy, ale jak zauważyły komentarze, ta funkcjonalność została od tego czasu wprowadzona do JDK, więc guawa nie jest już wymagana.
Jak widać, wersja Guava / JDK jest krótsza i unika zbędnych obiektów pomocniczych. W przypadku równości pozwala nawet na zwarcie oceny, jeśli wcześniejsze
Object.equals()
wywołanie zwróci fałsz (żeby być sprawiedliwym: commons / lang maObjectUtils.equals(obj1, obj2)
metodę o identycznej semantyce, której można użyć zamiastEqualsBuilder
zezwalać na zwarcie jak powyżej).A więc: tak, konstruktorzy języka wspólnego są bardziej preferowani niż ręcznie konstruowane
equals()
ihashCode()
metody (lub te okropne potwory, które wygeneruje dla ciebie Eclipse), ale wersje Java 7+ / Guava są jeszcze lepsze.I uwaga o Hibernate:
uważaj na używanie leniwych kolekcji w implementacjach equals (), hashCode () i toString (). To się nie powiedzie, jeśli nie masz otwartej sesji.
Uwaga (o równych ()):
a) w obu wersjach equals () powyżej możesz również chcieć użyć jednego lub obu tych skrótów:
b) w zależności od Twojej interpretacji umowy equals (), możesz również zmienić linię (y)
do
Jeśli używasz drugiej wersji, prawdopodobnie chcesz również wywołać
super(equals())
wewnątrz swojejequals()
metody. Zdania są tu różne, temat omawiany jest w tym pytaniu:(choć o to chodzi
hashCode()
, to samo dotyczyequals()
)Uwaga (inspirowana komentarzem od kayahr )
Objects.hashCode(..)
(podobnie jak podstawaArrays.hashCode(...)
) może działać źle, jeśli masz wiele pól pierwotnych. W takich przypadkachEqualsBuilder
może faktycznie być lepszym rozwiązaniem.źródło
equals
. Guawa konwertuje wszystkie wartości na obiekty, zwykły język tworzy tylko jeden nowy obiekt.Ludzie, obudźcie się! Od Java 7 istnieją metody pomocnicze dla równań i hashCode w bibliotece standardowej. Ich użycie jest w pełni równoważne z użyciem metod guawy.
źródło
Jeśli nie chcesz polegać na bibliotece innej firmy (może korzystasz z urządzenia z ograniczonymi zasobami), a nawet nie chcesz wpisywać własnych metod, możesz również pozwolić IDE wykonać zadanie, np. Przy użyciu zaćmienia
Dostaniesz „native” kod którą można skonfigurować jak chcesz, a które muszą obsługiwać na zmiany.
Przykład (zaćmienie Juno):
źródło
equals
. Jeśli nie chcesz polegać na bibliotece innej firmy, napisz metodęObjects.equal
jednowierszową, tak jak ty. Nawet jeśli jest używany tylko raz lub dwa razy, kod jest o wiele lepszy!equals
/hashCode
metody jednowierszowe ???EqualsBuilder i HashCodeBuilder mają dwa główne aspekty, które różnią się od kodu napisanego ręcznie:
EqualsBuilder i HashCodeBuilder ułatwiają porównywanie pól, które mogą mieć wartość null. Z ręcznie napisanym kodem tworzy to wiele schematów.
Z drugiej strony EqualsBuilder utworzy wystąpienie dla wywołania metody equals. Jeśli metody equals są często wywoływane, spowoduje to powstanie wielu instancji.
W przypadku hibernacji implementacja equals i hashCode nie ma znaczenia. To tylko szczegół implementacji. W przypadku prawie wszystkich obiektów domeny załadowanych w trybie hibernacji, narzut czasu wykonywania (nawet bez analizy ucieczki) Konstruktora można zignorować . Koszty bazy danych i komunikacji będą znaczące.
Jak wspomniał skaffman, wersja refleksji nie może być używana w kodzie produkcyjnym. Refleksja będzie zbyt wolna, a „implementacja” nie będzie poprawna dla wszystkich klas poza najprostszymi. Uwzględnianie wszystkich członków jest również niebezpieczne, ponieważ nowo wprowadzani członkowie zmieniają zachowanie metody equals. Wersja odbicia może być przydatna w kodzie testowym.
źródło
Jeśli nie napiszesz własnego, istnieje również możliwość korzystania z google guava (dawniej kolekcje Google)
źródło
Jeśli masz do czynienia tylko z komponentem bean encji, w którym identyfikator jest kluczem podstawowym, możesz uprościć.
źródło
Moim zdaniem nie współgra to dobrze z Hibernate, zwłaszcza przykłady z odpowiedzi porównujące długość, imię i dzieci dla jakiejś jednostki. Hibernate zaleca użycie klucza biznesowego używanego w equals () i hashCode () i mają swoje powody. Jeśli używasz generatora auto equals () i hashCode () w swoim kluczu biznesowym, wszystko jest w porządku, wystarczy rozważyć problemy z wydajnością, jak wspomniano wcześniej. Ale ludzie zwykle używają wszystkich właściwości, co jest bardzo złe w IMO. Na przykład obecnie pracuję nad projektem, w którym encje są pisane przy użyciu Pojomatic z @AutoProperty, co uważam za naprawdę zły wzorzec.
Ich dwa główne scenariusze użycia hashCode () i equals () to:
Załóżmy więc, że nasz byt wygląda tak:
Obie są tą samą jednostką dla Hibernate, które zostały w pewnym momencie pobrane z pewnej sesji (ich identyfikator i klasa / tabela są równe). Ale kiedy zaimplementujemy auto equals () a hashCode () na wszystkich właściwościach, co otrzymamy?
Tak więc dla 99% projektu, który wykonuję, używamy następującej implementacji equals () i hashCode () zapisanych raz w podstawowej klasie encji, co jest zgodne z koncepcjami Hibernate:
Dla bytu przejściowego robię to samo, co Hibernate zrobi na kroku trwałości, tj. Używam dopasowania instancji. W przypadku obiektów trwałych porównuję klucz unikalny, którym jest table / id (nigdy nie używam kluczy złożonych).
źródło
Na wszelki wypadek, inni uznają to za przydatne, wymyśliłem tę klasę Helper do obliczania kodu skrótu, która pozwala uniknąć dodatkowego narzutu tworzenia obiektów wspomnianego powyżej (w rzeczywistości narzut metody Objects.hash () jest jeszcze większy, gdy masz dziedziczenie, ponieważ utworzy nową tablicę na każdym poziomie!).
Przykład użycia:
Pomocnik HashCode:
Doszedłem do wniosku, że 10 to maksymalna rozsądna liczba właściwości w modelu domeny, jeśli masz więcej, powinieneś pomyśleć o refaktoryzacji i wprowadzeniu większej liczby klas zamiast utrzymywania stosu ciągów znaków i prymitywów.
Wady są następujące: nie jest to przydatne, jeśli masz głównie prymitywy i / lub tablice, które musisz głęboko haszować. (Zwykle dzieje się tak, gdy masz do czynienia z płaskimi (przenoszonymi) przedmiotami, które są poza twoją kontrolą).
źródło