Pytanie Co to jest serialVersionUID i dlaczego powinienem go używać?


Eclipse wydaje ostrzeżenia, gdy serialVersionUID brakuje.

Serializowana klasa Foo nie deklaruje statycznego finału   serialVersionUID pole typu long

Co jest serialVersionUID i dlaczego jest to ważne? Proszę pokazać przykład, w którym brakuje serialVersionUID spowoduje problem.


2489
2017-11-12 23:24


pochodzenie


Prosty przykład mkyong.com/java-best-practices/understand-the-serialversionuid - Gopinagh.R


Odpowiedzi:


Dokumenty dla java.io.Serializable są prawdopodobnie tak dobrym wyjaśnieniem jak:

Środowisko wykonawcze związane z serializacją jest powiązane   z każdą serializowalną klasą wersję   numer, zwany identyfikatorem seryjnym,   który jest używany podczas deserializacji   w celu sprawdzenia, czy nadawca i odbiorca   serializowanego obiektu zostały załadowane   klasy dla tego obiektu   zgodny z   serializacja. Jeśli odbiornik ma   załadował klasę dla obiektu, który ma   inny identyfikator interfejsu szeregowego niż to   odpowiedniej klasy nadawcy,   następnie deserializacja spowoduje    InvalidClassException. Serializowalny   klasa może zadeklarować własną   serialVersionUID jawnie przez   deklarowanie pola o nazwie   "serialVersionUID" to musi być   statyczne, końcowe i typu long:

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

Jeśli   klasa serializowalna nie jawnie   deklaruje serialVersionUID, a następnie   w środowisku wykonawczym serializacji zostanie obliczona wartość a   domyślna wartość serialVersionUID dla   ta klasa oparta na różnych aspektach   klasa, jak opisano w   Serializacja obiektów Java (TM)   Specyfikacja. Jednak tak jest silnie   Zalecana to wszystko można serializować   klasy jawnie deklarują   wartości serialVersionUID, ponieważ   domyślne obliczenia szeregowej wersji   jest bardzo wrażliwy na szczegóły klasy   które mogą się różnić w zależności od kompilatora   implementacje, a zatem może wyniknąć   w nieoczekiwany InvalidClassExceptions   podczas deserializacji. Dlatego do   gwarantować spójność   wartość serialVersionUID w poprzek   inny kompilator java   implementacje, klasa nadająca się do serializacji   musi zadeklarować wyraźne   wartość serialVersionUID. To jest również   zdecydowanie zaleca to wyraźne   deklaracje serialVersionUID używają   modyfikator prywatny, jeśli to możliwe, ponieważ   takie deklaracje mają zastosowanie tylko do   natychmiast deklarując   class - serialVersionUID pola nie są   przydatne jako dziedziczeni członkowie.


1911
2017-11-12 23:30



Więc, co zasadniczo mówisz, to że jeśli użytkownik nie zrozumiał wszystkich powyższych materiałów, użytkownik nie martwił się o serializację? Wierzę, że odpowiedziałeś na pytanie "jak?" zamiast wyjaśniać "dlaczego?". Po pierwsze, nie rozumiem, dlaczego mam kłopot z SerializableVersionUID. - Ziggy
Dlaczego jest w drugim akapicie: jeśli nie określisz jawnie serialVersionUID, wartość jest generowana automatycznie - ale jest to krucha, ponieważ zależy od implementacji kompilatora. - Jon Skeet
I dlaczego Eclipse mówi, że potrzebuję "prywatnego statycznego końcowego długiego serialVersionUID = 1L;" kiedy rozszerzam klasę Exception? - JohnMerlino
@JohnMerlino: Nie spodziewałbym się, że ci to powie potrzeba jeden - ale może być sugestia jeden, aby pomóc ci poprawnie serializować wyjątki. Jeśli nie zamierzasz ich serializować, naprawdę nie potrzebujesz stałej. - Jon Skeet
@JohnMerlino, aby odpowiedzieć na pytanie, dlaczego część z was pytanie: narzędzia Exception Serializable i eclipse ostrzega, że ​​nie ustawiłeś serialVersionUID, co byłoby dobrym pomysłem (jeśli nie chcesz serializować klasy), aby uniknąć problemów, które kontury JonSkeet's kontury. - zpon


Jeśli serializujesz tylko dlatego, że musisz serializować dla implementacji (kogo to obchodzi jeśli serializujesz dla HTTPS, na przykład ... jeśli jest przechowywany czy nie, prawdopodobnie nie dbasz o dekompresowanie obiektu formularza) , możesz to zignorować.

Jeśli rzeczywiście używasz serializacji, ma to znaczenie tylko, jeśli planujesz przechowywanie i pobieranie obiektów bezpośrednio przy użyciu serializacji. SerialVersionUID reprezentuje twoją wersję klasy i powinieneś ją zwiększyć, jeśli aktualna wersja twojej klasy nie jest wstecznie zgodna z jej poprzednią wersją.

Przez większość czasu prawdopodobnie nie będziesz używać serializacji bezpośrednio. W takim przypadku wygeneruj domyślny identyfikator seryjny, klikając opcję szybkiej poprawki i nie przejmuj się tym.


415
2017-11-13 04:24



Powiedziałbym, że jeśli nie używasz serializacji do przechowywania na stałe, powinieneś raczej używać @SuppressWarnings zamiast dodawać wartość. Zaśmieca klasę mniej, a zachowuje ona właściwość mechanizmu serialVersionUID, aby chronić Cię przed niekompatybilnymi zmianami. - Tom Anderson
Nie widzę, jak dodanie jednej linii (adnotacja @SuppressWarnings) w przeciwieństwie do innej linii (identyfikator serializowalny) "zaśmieca klasę mniej". A jeśli nie używasz serializacji do trwałego przechowywania, dlaczego nie po prostu użyjesz "1"? W takim razie nie przejmowałbyś się automatycznie wygenerowanym identyfikatorem. - MetroidFan2002
@ MetroidFan2002: Myślę, że punkt TomAnderson jest serialVersionUID ochrona Cię przed niezgodnymi zmianami jest ważna. Za pomocą @SuppressWarnings dokumentuje zamiar lepiej, jeśli nie chcesz używać klasy do stałego przechowywania. - AbdullahC
"Powinieneś go zwiększyć, jeśli aktualna wersja twojej klasy nie jest wstecznie kompatybilna z poprzednią wersją:" Powinieneś najpierw zbadać obsługę szeregowania obiektowego serializacji, (a), aby upewnić się, że klasa naprawdę jest teraz niekompatybilna z serializacją, które zgodnie ze specyfikacją jest dość trudne do osiągnięcia; (b) wypróbowanie schematu takiego jak niestandardowe metody read / writeObject (), metody readResolve / writeReplace (), deklaracje serializableFields itp., aby upewnić się, że strumień pozostaje zgodny. Zmiana rzeczywistego serialVersionUID jest ostatnią deską ratunku, radą rozpaczy. - user207421
Przyrostek @EJP z serialVersionUID pojawia się w obrazie, gdy pierwotny autor klasy wprowadził jawnie. Powiedziałbym, że wygenerowany seryjny identyfikator jvm powinien być w porządku. to jest najlepszy odpowiedź które widziałem w serializacji. - overexchange


Nie mogę przepuścić okazji, żeby podłączyć książkę Josha Blocha Efektywna Java (Wydanie drugie). Rozdział 11 jest nieodzownym źródłem serializacji Java.

Per Josh automatycznie generowany identyfikator UID jest generowany na podstawie nazwy klasy, zaimplementowanych interfejsów oraz wszystkich publicznych i chronionych członków. Zmiana któregokolwiek z nich w jakikolwiek sposób zmieni serialVersionUID. Nie musisz więc z nimi mieszać, tylko jeśli masz pewność, że nie więcej niż jedna wersja klasy zostanie kiedykolwiek przekształcona do postaci szeregowej (albo w ramach procesów, albo w późniejszym czasie pobrana z magazynu).

Jeśli na razie je zignorujesz, a później okaże się, że musisz zmienić klasę w jakiś sposób, ale zachowujesz zgodność ze starszą wersją klasy, możesz użyć narzędzia JDK seryjny wygenerować serialVersionUID na stary klasy i wyraźnie ustawić to na nowej klasie. (W zależności od zmian konieczne może być również wdrożenie niestandardowej serializacji poprzez dodanie writeObject i readObject metody - patrz Serializable javadoc lub wspomniany wcześniej rozdział 11.)


264
2017-11-12 23:37



Czy ktoś może martwić się SerializableVersionUID, jeśli chodzi o kompatybilność ze starszymi wersjami klasy? - Ziggy
Tak, na wypadek, gdyby nowsza wersja zmieniła dowolnego członka publicznego chronionego, domyślny ID SerializableVersionU będzie inny i podniesie InvalidClassExceptions. - Chander Shivdasani
Nazwa klasy, zaimplementowane interfejsy, wszystkie metody publiczne i chronione, WSZYSTKIE zmienne instancji. - Achow
Warto zauważyć, że Joshua Bloch doradza, że każdy Serializowalna klasa warta jest określenia wersji seryjnej uid. Cytat z rozdziału 11: Bez względu na to, jaką wybierzesz serializację, zadeklaruj jawną seryjną wersję UID w każdej serializowalnej klasie, którą piszesz. Eliminuje to numer seryjny UID jako potencjalne źródło niekompatybilności (pozycja 74). Istnieje także niewielka korzyść z wydajności. Jeśli nie podano UID wersji szeregowej, wymagane jest kosztowne obliczenie w celu wygenerowania jednego w czasie wykonywania. - Ashutosh Jindal


Możesz powiedzieć Eclipse, aby zignorował ostrzeżenia o tych serialVersionUID:

Okno> Preferencje> Java> Kompilator> Błędy / ostrzeżenia> Problemy z programowaniem potencjału

Jeśli nie wiesz, istnieje wiele innych ostrzeżeń, które możesz włączyć w tej sekcji (lub nawet niektóre z nich są zgłaszane jako błędy), wiele z nich jest bardzo użytecznych:

  • Potencjalne problemy z programowaniem: Możliwe przypadkowe przypisanie boolowskie
  • Możliwości związane z programowaniem: zerowy dostęp do wskaźnika
  • Niepotrzebny kod: Lokalna zmienna nigdy nie jest czytana
  • Niepotrzebny kod: Nadmiarowa kontrola zerowa
  • Niepotrzebny kod: niepotrzebna obsada lub "instanceof"

i wiele więcej.


124
2017-11-13 01:17



przejęcie, ale tylko dlatego, że oryginalny plakat nie wydaje się być serializacją czegokolwiek. Jeśli na plakacie napisano "serializuję tę rzecz i ...", zamiast tego zamiast tego otrzymasz głos: P - John Gardner
To prawda - zakładałem, że pytający po prostu nie chce być ostrzeżony - matt b
@Gardner -> uzgodniony! Ale pytający chce także wiedzieć, dlaczego nie chciałby zostać ostrzeżony. - Ziggy
Pytający oczywiście troszczy się o to, dlaczego powinien istnieć UID. Więc po prostu powiedz mu, żeby zignorował ostrzeżenie, powinno zostać odrzucone. - cinqS


serialVersionUID ułatwia wersjonowanie zserializowanych danych. Jego wartość jest przechowywana wraz z danymi podczas serializacji. Podczas deklasyfikacji ta sama wersja jest sprawdzana, aby zobaczyć, jak zserializowane dane pasują do bieżącego kodu.

Jeśli chcesz zmienić swoje dane, zwykle zaczynasz od serialVersionUID 0 i potrącić go o każdą zmianę strukturalną w twojej klasie, która zmienia zserializowane dane (dodawanie lub usuwanie nieprzejściowych pól).

Wbudowany mechanizm deklinalizacji (in.defaultReadObject()) odmówi odseparowania starszych wersji danych. Ale jeśli chcesz, możesz zdefiniować własne readObject ()-funkcja, która może odczytywać stare dane. Ten niestandardowy kod może następnie sprawdzić serialVersionUID aby dowiedzieć się, w której wersji znajdują się dane i zdecydować, jak je rozdzielić. Ta technika kontroli wersji jest przydatna, jeśli przechowujesz dane szeregowe, które przetrwały kilka wersji kodu.

Jednak przechowywanie danych zserializowanych przez tak długi czas nie jest powszechne. O wiele częściej korzysta się z mechanizmu serializacji, aby tymczasowo zapisywać dane na przykład w pamięci podręcznej lub przesyłać je przez sieć do innego programu z tą samą wersją odpowiednich części kodu.

W tym przypadku nie jesteś zainteresowany zachowaniem kompatybilności wstecznej. Zajmujesz się tylko upewnianiem się, że podstawa kodu, która się komunikuje, rzeczywiście ma te same wersje odpowiednich klas. Aby ułatwić taką kontrolę, musisz zachować serialVersionUIDtak jak wcześniej i nie zapomnij zaktualizować go, wprowadzając zmiany na twoich zajęciach.

Jeśli zapomnisz zaktualizować pole, możesz skończyć z dwiema różnymi wersjami klasy o innej strukturze, ale z tymi samymi serialVersionUID. Jeśli tak się stanie, domyślny mechanizm (in.defaultReadObject()) nie wykryje żadnej różnicy i spróbuje rozdzielić dane niekompatybilne. Teraz możesz skończyć z tajemniczym błędem wykonawczym lub cichą awarią (puste pola). Tego rodzaju błędy mogą być trudne do znalezienia.

Aby pomóc w tym przypadku, platforma Java oferuje wybór nie ustawienia serialVersionUID ręcznie. Zamiast tego, mieszanie struktury klasy zostanie wygenerowane podczas kompilacji i użyte jako id. Mechanizm ten zapewni, że nigdy nie będziesz mieć różnych struktur klas o tym samym identyfikatorze, a więc nie otrzymasz tych trudnych do śledzenia niepowodzeń serializacji w czasie wykonywania wymienionych powyżej.

Ale jest też backside do automatycznie generowanej strategii id. Mianowicie, że wygenerowane identyfikatory dla tej samej klasy mogą się różnić między kompilatorami (jak wspomniano wyżej przez Jona Skeeta). Jeśli więc komunikujesz serializowane dane między kodem skompilowanym z różnymi kompilatorami, zaleca się, aby mimo to zachować identyfikatory.

A jeśli dane są kompatybilne wstecz z danymi, jak w pierwszym przypadku użycia, prawdopodobnie również chcesz zachować identyfikator samodzielnie. Aby uzyskać czytelne identyfikatory i mieć większą kontrolę nad tym, kiedy i jak się zmieniają.


96
2017-10-03 06:05



Dodanie lub usunięcie nieprzejściowych pól nie powoduje niezgodności serializacji klas. Nie ma zatem powodu, by "uderzać" w takie zmiany. - user207421
@EJP: Huh? Dodanie danych zdecydowanie zmienia dane serializacji w moim świecie. - Alexander Torstling
@AlexanderTorstling Przeczytaj, co napisałem. Nie powiedziałem, że to nie "zmienia danych serializacji". Powiedziałem, że "nie czyni serializacji niekompatybilną z serią". To nie to samo. Konieczne jest przeczytanie rozdziału Wersja specyfikacji obiektowej szeregowania. - user207421
@EJP: Zdaję sobie sprawę, że dodanie nieprzejściowego pola nie musi oznaczać, że uczynisz serializację klasy niekompatybilną, ale jest to strukturalna zmiana, która zmienia zserializowane dane i zwykle chcesz podnieść wersję, jeśli to robisz, chyba że obsługiwać kompatybilność wsteczną, którą wyjaśniłem później w poście. O co ci dokładnie chodzi? - Alexander Torstling
Moja uwaga pozostaje dokładnie tym, co powiedziałem. Dodanie lub usunięcie nieprzejściowych pól nie powoduje, że serializacja klas jest niekompatybilna. W związku z tym nie trzeba podnosić numeru seryjnego za każdym razem. - user207421


Co to jest serialVersionUID i dlaczego powinienem go używać?

SerialVersionUID jest unikalnym identyfikatorem dla każdej klasy, JVM używa go do porównywania wersji klasy, zapewniając, że ta sama klasa była używana podczas serializacji podczas ładowania.

Podanie jednego daje większą kontrolę, chociaż JVM generuje jedną, jeśli jej nie określisz. Wygenerowana wartość może się różnić między różnymi kompilatorami. Ponadto, czasami po prostu chcesz z jakiegoś powodu zabronić deserializacji starych serializowanych obiektów [backward incompatibility], w tym przypadku wystarczy zmienić identyfikator serialVersionUID.

The javadocs dla Serializable mówić:

domyślne obliczenia serialVersionUID są bardzo wrażliwe na klasy   szczegóły, które mogą się różnić w zależności od implementacji kompilatora i może   skutkuje to nieoczekiwanym InvalidClassExceptions podczas   deserializacja.

Dlatego musisz zadeklarować serialVersionUID, ponieważ daje nam większą kontrolę.

Ten artykuł ma kilka dobrych punktów na ten temat.


62
2017-10-17 04:28



@Vinothbabu, ale serialVersionUID jest statyczny, więc zmienne statyczne nie mogą być serializowane. jak to się stanie, że jvm sprawdzi wersję, nie wiedząc, jaka jest wersja deserializującego obiektu - Kranthi Sama
Jedyną rzeczą, o której nie wspomniano w tej odpowiedzi, jest to, że możesz spowodować niezamierzone konsekwencje, włączając ślepo serialVersionUID nie wiedząc dlaczego. Komentarz Toma Andersona na temat odpowiedzi MetroidFan2002 brzmi następująco: "Powiedziałbym, że jeśli nie używasz serializacji do trwałego przechowywania, powinieneś raczej używać @SuppressWarnings zamiast dodawać wartość.Ale to klasyfikuje mniej, a zachowuje zdolność Mechanizm serialVersionUID chroniący przed niekompatybilnymi zmianami. " - Kirby
serialVersionUID jest nie "niepowtarzalny identyfikator dla każdej klasy". Jest to w pełni kwalifikowana nazwa klasy. To jest wersja wskaźnik. - user207421


Pierwotne pytanie wymagało odpowiedzi "dlaczego jest to ważne" i "przykład" Serial Version ID byłoby przydatne. Cóż, znalazłem jeden.

Powiedz, że tworzysz Car klasa, stwórz instancję i zapisz ją do strumienia obiektów. Spłaszczony obiekt samochodu od pewnego czasu znajduje się w systemie plików. Tymczasem, jeśli Car klasa jest modyfikowana poprzez dodanie nowego pola. Później, kiedy spróbujesz odczytać (to jest deserializować) spłaszczone Car obiekt, dostaniesz java.io.InvalidClassException - ponieważ wszystkie klasy serializowalne otrzymują automatycznie unikalny identyfikator. Ten wyjątek jest generowany, gdy identyfikator klasy nie jest równy identyfikatorowi spłaszczonego obiektu. Jeśli naprawdę o tym pomyślisz, wyjątek zostanie zgłoszony z powodu dodania nowego pola. Możesz uniknąć wyrzucenia tego wyjątku, kontrolując samą wersję, deklarując jawny serialVersionUID. Istnieje także niewielka zasiłka za wydajność w jawnym deklarowaniu Twojego serialVersionUID(ponieważ nie musi być obliczana). Najlepiej więc dodać własny serialVersionUID do klas Serializable, gdy tylko je utworzysz, jak pokazano poniżej:

public class Car {
static final long serialVersionUID = 1L; //assign a long value
}

42
2018-04-07 10:43



I należy przypisać losową długą liczbę, a nie 1L, do każdego UID. - abbas
@abbas "Trzeba" to zrobić, dlaczego? Proszę wyjaśnić, na czym polega różnica. - user207421
Jak sama nazwa wskazuje, reprezentuje wersję klasy, która została użyta do serializacji obiektu. Jeśli za każdym razem przydzielisz mu ten sam numer, nie będziesz w stanie znaleźć właściwej klasy, aby zdekantować go. Kiedy więc zmienisz klasę, lepiej też zmienić wersję. - abbas
@abbas, zamiar ten nie koliduje z używaniem rosnących liczb naturalnych z 1 i tak dalej. - Vadzim
@BillK, myślałem, że sprawdzanie serializacji jest powiązane z parą classname i serialVersionUID. Tak więc różne schematy numerowania różnych klas i bibliotek nie mogą w żaden sposób ingerować. Czy sugerowałeś biblioteki kodujące? - Vadzim


Jeśli otrzymasz to ostrzeżenie na lekcji, nigdy nie myślisz o serializowaniu i że nie zadeklarowałeś siebie implements Serializable, często dzieje się tak dlatego, że odziedziczyłeś po nadklasie, która implementuje Serializable. Często byłoby lepiej delegować do takiego obiektu zamiast używać dziedziczenia.

Zamiast tego

public class MyExample extends ArrayList<String> {

    public MyExample() {
        super();
    }
    ...
}

zrobić

public class MyExample {
    private List<String> myList;

    public MyExample() {
         this.myList = new ArrayList<String>();
    }
    ...
}

i w odpowiednich metodach wywołaj myList.foo() zamiast this.foo() (lub super.foo()). (To nie pasuje do wszystkich przypadków, ale wciąż dość często.)

Często widzę ludzi, którzy rozszerzają JFrame lub takie, kiedy tak naprawdę muszą tylko delegować na to. (Pomaga to również w autouzupełnianiu w IDE, ponieważ JFrame ma setki metod, których nie potrzebujesz, gdy chcesz wywoływać niestandardowe w swojej klasie.)

Jeden przypadek, w którym ostrzeżenie (lub serialVersionUID) jest nieuchronne, dotyczy rozszerzenia z AbstractAction, zwykle w klasie anonimowej, z dodaniem metody actionPerformed. Myślę, że w tym przypadku nie powinno być ostrzeżenia (ponieważ normalnie nie można niezawodnie serializować ani deserializować takich anonimowych klas wbrew różnym wersjom twojej klasy), ale nie jestem pewien, jak kompilator mógł to rozpoznać.


33
2018-02-03 00:32



Sądzę, że masz rację, że kompozycja na temat inhalacji ma więcej sensu, szczególnie gdy omawiasz takie klasy, jak ArrayList. Wiele szkieletów wymaga jednak rozszerzenia od abstrakcyjnych superklatek, które można serializować (takich jak klasa ActionForm w Struts 1.2 lub Saxon's ExtensionFunctionDefinition), w których to rozwiązanie jest niemożliwe. Myślę, że masz rację, byłoby miło, gdyby ostrzeżenie zostało zignorowane w pewnych przypadkach (na przykład, gdy rozszerzałeś się z abstrakcyjnej klasy serializowanej) - piepera
Z pewnością, jeśli dodasz klasę jako członka, zamiast dziedziczyć z niej, będziesz musiał napisać metodę wrapper dla KAŻDEJ metody klasy członka, którą chciałbyś użyć, co uczyniłoby ją niewykonalną w wielu sytuacjach. chyba że java ma funkcję podobną do perla __AUTOLOAD, o czym nie wiem. - M_M
@M_M: Gdy delegowałbyś wiele metod do zawiniętego obiektu, oczywiście nie byłoby właściwe korzystanie z delegowania. Przypuszczam jednak, że ten przypadek jest oznaką pomyłki projektowej - użytkownicy twojej klasy (np. "MainGui") nie powinni wywoływać wielu metod zawijanego obiektu (np. JFrame). - Paŭlo Ebermann
To, co nie podoba mi się w delegacji, to konieczność posiadania odniesienia do delegata. A każde odniesienie oznacza więcej pamięci. Popraw mnie, jeśli się mylę. Jeśli potrzebuję CustomizedArrayList z 100 obiektów, nie ma to większego znaczenia, ale jeśli potrzebuję setek CustomizdeArrayLists kilku obiektów, to użycie pamięci znacznie wzrośnie. - WVrock
Opcja Throwable jest przekształcalna do postaci szeregowej, a tylko Throwble jest dostępna, więc nie można zdefiniować wyjątku, którego nie można przekształcić do postaci szeregowej. Delegacja nie jest możliwa. - Phil


Jeśli nigdy nie będziesz musiał serializować obiektów do tablicy bajtów i wysyłać / przechowywać ich, to nie musisz się tym martwić. Jeśli tak, to musisz wziąć pod uwagę swój serialVersionUID, ponieważ deserializator obiektu dopasuje go do wersji obiektu, który posiada jego moduł ładujący klasy. Przeczytaj więcej na ten temat w specyfikacji języka Java.


30
2017-11-12 23:30



Jeśli nie zamierzasz serializować obiektów, dlaczego są one Serializable? - erickson
@erickson - klasa nadrzędna może być przekształcalna do postaci szeregowej, np. ArrayList, ale chcesz, aby Twój własny obiekt (np. zmodyfikowana lista tablic) używał jej jako bazy, ale nigdy nie będzie serializować tworzonej kolekcji. - MetroidFan2002
Nie jest on nigdzie wymieniony w specyfikacji języka Java. Zostało to wspomniane w specyfikacji wersji obiektu. - user207421
Oto link do Java 8 Specyfikacja wersji obiektu. - Basil Bourque