Operator diamentów w java 7 zezwala na kod podobny do następującego:
List<String> list = new LinkedList<>();
Jednak w Javie 5/6 mogę po prostu napisać:
List<String> list = new LinkedList();
Rozumiem, że typ kasowania jest taki sam. (Generic i tak zostaje usunięty w czasie wykonywania).
Po co w ogóle zawracać sobie głowę diamentem? Jakie nowe funkcje / bezpieczeństwo typu pozwala? Jeśli nie daje żadnej nowej funkcjonalności, dlaczego wspominają o tym jako o funkcji? Czy moje rozumienie tej koncepcji jest wadliwe?
java
generics
java-7
diamond-operator
tofarr
źródło
źródło
Odpowiedzi:
Problem z
jest to, że po lewej stronie używasz typu ogólnego, a
List<String>
po prawej stronie używasz typu surowegoLinkedList
. Surowe typy w Javie istnieją tylko dla kompatybilności z kodem pre-generics i nigdy nie powinny być używane w nowym kodzie, chyba że jest to absolutnie konieczne.Teraz, jeśli Java miała generyczne od samego początku i nie miała typów, takich jak te
LinkedList
, które zostały pierwotnie utworzone, zanim miała generyczne, prawdopodobnie mogłaby to zrobić, aby konstruktor typu ogólnego automatycznie ustawiał parametry typu od lewej -ręczna strona zadania, jeśli to możliwe. Ale tak się nie stało i musi traktować typy surowe i typy ogólne inaczej dla kompatybilności wstecznej. To sprawia, że muszą stworzyć nieco inny , ale równie wygodny sposób deklarowania nowej instancji obiektu ogólnego bez konieczności powtarzania parametrów typu ... operator diamentu.Jeśli chodzi o oryginalny przykład
List<String> list = new LinkedList()
, kompilator generuje ostrzeżenie dla tego zadania, ponieważ musi. Rozważ to:Istnieją środki generyczne, które zapewniają ochronę podczas kompilacji przed robieniem złych rzeczy. W powyższym przykładzie użycie typu raw oznacza, że nie otrzymujesz tej ochrony i wystąpi błąd w czasie wykonywania. Dlatego nie powinieneś używać typów surowych.
Operator diamentów pozwala jednak zdefiniować prawą stronę przypisania jako prawdziwą ogólną instancję z tymi samymi parametrami typu co lewa strona ... bez konieczności ponownego wpisywania tych parametrów. Pozwala zachować bezpieczeństwo leków generycznych przy prawie takim samym wysiłku jak przy użyciu typu raw.
Myślę, że kluczową rzeczą do zrozumienia jest to, że typy surowe (bez
<>
) nie mogą być traktowane tak samo jak typy ogólne. Po zadeklarowaniu typu surowego nie uzyskuje się żadnych korzyści ani sprawdzania typu generyków. Trzeba też pamiętać, że generyczne są częścią języka Java ogólnego przeznaczenia ... nie dotyczą tylko konstruktorów bez argonuCollection
!źródło
-compatibility
przełącznika kompilatora, a jeśli go niejavac
ma, zabroni wszystkich typów surowych i wymusi wyłącznie typy ściśle ogólne? To sprawi, że nasze kody będą mniej szczegółowe.List<String> strings = new List<>()
jest OK, ale jeśli zdefiniujeszprivate List<String> my list;
, a następnie w połowie strony, z której tworzona jest instancjamy_list = new List<>()
, nie będzie fajnie! Co znowu zawiera moja lista? Och, pozwól mi poszukać definicji. Nagle korzyść ze skrótu diamentowego zostaje do widzenia.my_list = getTheList()
? Istnieje kilka lepszych sposobów radzenia sobie z tego rodzaju problemami: 1. użyj IDE, które pokazuje typy zmiennych po najechaniu myszą. 2. używaj bardziej znaczących nazw zmiennych, takich jakprivate List<String> strings
3. nie dziel deklaracji i inicjalizacji zmiennych, chyba że naprawdę musisz.Twoje zrozumienie jest nieco błędne. Operator diamentów jest fajną funkcją, ponieważ nie musisz się powtarzać. Wskazane jest zdefiniowanie typu raz, kiedy deklarujesz typ, ale po prostu nie ma sensu definiowanie go ponownie po prawej stronie. Zasada DRY.
Teraz wyjaśnię wszystkie problemy związane z definiowaniem typów. Masz rację, że typ jest usuwany w czasie wykonywania, ale gdy chcesz odzyskać coś z listy z definicją typu, odzyskujesz go jako typ zdefiniowany podczas deklarowania listy, w przeciwnym razie straciłby wszystkie określone funkcje i miałby tylko Funkcje obiektu, z wyjątkiem sytuacji, gdy odrzuciłeś pobrany obiekt do jego oryginalnego typu, co czasami może być bardzo trudne i skutkować wyjątkiem ClassCastException.
Użycie
List<String> list = new LinkedList()
spowoduje wyświetlenie ostrzeżeń typu raw.źródło
List<String> list = new LinkedList()
jest poprawnym kodem. Ty to wiesz i ja też to wiem. Pytanie (jak rozumiem) brzmi: dlaczego tylko kompilator Java nie rozumie, że ten kod jest dość bezpieczny?List<String> list = new LinkedList()
jest nie prawidłowy kod. Jasne, byłoby miło, gdyby tak było! I prawdopodobnie mogłoby tak być, gdyby Java miała od początku generyczne i nie musiała zajmować się wsteczną kompatybilnością typów generycznych, które kiedyś nie były ogólne, ale tak jest.<?>
jeśli interfejs do starszego kodu), a bezużyteczny operator diamentów nie powinien istnieć.Ta linia powoduje ostrzeżenie [niezaznaczone]:
Pytanie zmienia się: dlaczego [niezaznaczone] ostrzeżenie nie jest automatycznie tłumione tylko w przypadku, gdy tworzona jest nowa kolekcja?
Myślę, że byłoby to znacznie trudniejsze zadanie niż dodanie
<>
funkcji.UPD : Myślę również, że byłoby bałagan, gdyby legalnie używać surowych typów „tylko dla kilku rzeczy”.
źródło
Teoretycznie operator diamentów pozwala pisać bardziej zwarty (i czytelny) kod, zapisując argumenty typu powtarzanego. W praktyce to tylko dwa mylące znaki, które nie dają nic. Dlaczego?
IMHO, mając jasny i prosty sposób na oznaczenie źródła jako Java 7, byłoby bardziej przydatne niż wymyślanie takich dziwnych rzeczy. W tak oznaczonym kodzie surowe typy mogą być zakazane bez utraty niczego.
Przy okazji, nie sądzę, że należy to zrobić za pomocą przełącznika kompilacji. Wersja pliku Java programu jest atrybutem pliku, bez żadnej opcji. Używanie czegoś tak trywialnego jak
może to wyjaśnić (możesz preferować coś bardziej wyrafinowanego, w tym jedno lub więcej fantazyjnych słów kluczowych). Pozwoliłoby to nawet na kompilację źródeł napisanych dla różnych wersji Java bez żadnych problemów. Umożliwiłoby to wprowadzenie nowych słów kluczowych (np. „Moduł”) lub upuszczenie niektórych przestarzałych funkcji (wiele niepublicznych niepasowanych klas w jednym pliku lub w ogóle) bez utraty kompatybilności.
źródło
new ArrayList(anotherList)
anew ArrayList<>(anotherList)
zwłaszcza jeśli jest on przypisany doList<String>
ianotherList
jest aList<Integer>
)?new @RawType List()
. To już poprawna składnia Java 8 i adnotacje typu pozwalają na użycie jej w każdym miejscu, gdzie jest to potrzebne, np@RawType List = (@RawType List) genericMethod();
. Biorąc pod uwagę, że typy surowe obecnie tworzą ostrzeżenie kompilatora, chyba że@SuppressWarnings
zostanie umieszczony odpowiedni,@RawType
byłoby rozsądnym zamiennikiem i nie jest potrzebna bardziej subtelna składnia.Podczas pisania
List<String> list = new LinkedList();
kompilator generuje ostrzeżenie „niezaznaczone”. Możesz to zignorować, ale jeśli zignorowałeś te ostrzeżenia, możesz również przeoczyć ostrzeżenie, które powiadamia o prawdziwym problemie z bezpieczeństwem.Lepiej więc napisać kod, który nie generuje dodatkowych ostrzeżeń, a operator diamentów pozwala to zrobić w wygodny sposób bez zbędnego powtarzania.
źródło
Wszystkie powiedziane w pozostałych odpowiedziach są prawidłowe, ale przypadki użycia nie są całkowicie poprawne IMHO. Jeśli ktoś sprawdzi Guawę, a zwłaszcza rzeczy związane ze zbiorami, to samo zrobiono metodami statycznymi. Np. Lists.newArrayList (), który pozwala pisać
lub ze statycznym importem
Guava ma inne bardzo potężne funkcje, takie jak ta, i właściwie nie mogę wymyślić wielu zastosowań dla <>.
Byłoby bardziej użyteczne, gdyby zdecydowali się na ustawienie domyślnego zachowania operatora diamentu, to znaczy, że typ jest wywnioskowany z lewej strony wyrażenia lub jeśli typ z lewej strony został wywnioskowany z prawej strony. To ostatnie dzieje się w Scali.
źródło
Celem operatora diamentowego jest po prostu ograniczenie pisania kodu podczas deklarowania typów ogólnych. Nie ma to żadnego wpływu na środowisko uruchomieniowe.
Jedyna różnica, jeśli podasz w Javie 5 i 6,
jest to, że trzeba podać
@SuppressWarnings("unchecked")
dolist
(inaczej dostaniesz niesprawdzony ostrzeżenie szarego). Rozumiem, że operator diamentów stara się ułatwić rozwój. Nie ma to w ogóle nic wspólnego z wykonywaniem generycznych programów uruchomieniowych.źródło