2011-10-17 3 views
14

ziarnista POJO Java taki kod może być korzystne, zwłaszcza w kolekcji:Czy dobrą praktyką jest inicjowanie pól wewnątrz obiektu pobierającego jednostki JPA?

class POJO { 
    private Collection<X> col; 

    public Collection<X> getCol() { 
     if (col == null) 
      col = new SomeCollection<X>(); 

     return col; 
    } 
} 

Umożliwia kodu przy użyciu POJO zadzwonić pojo.getCol().isEmpty() bez dodatkowego sprawdzenia null, dzięki czemu kod jaśniejsze.

Załóżmy, że klasa POJO jest jednostką JPA, czy nadal jest to bezpieczne? Przez inicjalizację kolekcji od pustej do pustej dane trwałe nie zostaną zmienione, ale wciąż modyfikujemy obiekt, a zatem dostawca trwałości może wywoływać pewne skutki uboczne po wypłukaniu kontekstu utrwalania. Co ryzykujemy? Przenośność może?

Odpowiedz

10

Silnie odradzam leniwą inicjalizację dla właściwości w jednostce ORM.

Mieliśmy poważny problem podczas leniwego inicjowania właściwości obiektu za pomocą Hibernate, więc zdecydowanie odradzam. Problem, który widzieliśmy, przejawiał się w momencie, gdy wysyłaliśmy żądanie wyszukiwania. Wynika to z tego, że po załadowaniu obiektu właściwość miała wartość zerową, ale po wywołaniu gettera zwróciłaby ona zainicjowany obiekt leniwy, więc hibernacja (słusznie) uznała obiekt za brudny i zapisał go przed wydaniem wyszukiwania.

+0

Dzięki, tego właśnie szukałem - ostrzeżenia od kogoś, kto został spalony. Miałem przeczucie, że może być źle, tylko chciałem się upewnić, że nie fantazjowałem. – MaDa

+1

pewnie. Skończyło się na tym, że spędziliśmy 2 dni na śledzeniu, gdzie obiekt się brudził. To było dość bolesne. – digitaljoel

20

Nie uważam tego za dobrą praktykę, bardziej jako bardzo rzadko potrzebną optymalizację. Może leniwy inicjalizacji może mieć sens, jeśli SomeCollection jest bardzo ciężki do stworzenia. Zamiast tego można zainicjować gdy zadeklarowana (kod jest czystsze przynajmniej w moich oczach):

class POJO { 
    private Collection<X> col = new SomeCollection<X>(); 

    public Collection<X> getCol() { 
     return col; 
    } 
} 

Nie ma żadnych skutków ubocznych w kwestii gładkimi lub przenośności i masz jeden mniej sprawdzić wartość null.

2

Ogólnie dobrym pomysłem jest użycie pustych kolekcji zamiast lub null (dla pól, które są kolekcjami).

Ale nie polecam sposobu, w jaki robisz w gettera.

W mojej osobistej opinii powyższa "reguła" powinna być również użyta do wewnętrznej reprezentacji obiektu. Więc lepiej iść z:

class POJO { 
    private Collection<X> col = new SomeCollection<X>(); 

W każdym razie, jeśli chcesz chcesz uczynić go bardziej zaoszczędzić, trzeba pilnować każdy sposób zaktualizować odniesienie col. Ale w aplikacji WZP powinno to być bardzo surowym przypadkiem użycia.

1

Lazy inicjalizacja jest bardzo powszechne i dobrze zrobić.

Są kompromisy w porównaniu do inicjowania w konstruktorze lub definicji zmiennej:

Pro

  • leniwe inicjowanie jest na ogół bardziej skuteczne, to odracza koszty tworzenia wartości, które nigdy nie mogą być wymagane lub zastąpione inną wartością. Jest to bardzo powszechne w JPA, gdzie istniejący obiekt jest odczytywany z bazy danych, a ich wartości są zawsze zastępowane.
  • Pozwala to na określenie wartości pustej, co jest bardziej typowe dla wartości typu Boolean, gdzie wartość null oznacza wartość domyślną, która jest leniwie przypisywana w oparciu o coś innego, co nie jest znane w czasie tworzenia.
  • Jeśli wartość jest przejściowa lub nie ma pewności, jak leniwy plik inicjujący może zapobiegać wskaźnikom zerowym.

Con

  • Jeśli pole jest dostępne bezpośrednio można jeszcze dostać null-pointer.
  • Ustawienie domyślnej wartości w definicji zmiennej jest bardziej przejrzyste.
  • Jeśli obiekt jest używany jednocześnie, inicjalizacja leniwy może być problemem z współbieżnością.