2011-01-11 2 views
7

Niedawno natknąłem się na Javadoc dla rodziny Collection.checkedMap funkcji do tworzenia dynamicznie bezpiecznych widoków standardowych typów kolekcji. Biorąc pod uwagę, że dodają kolejną warstwę bezpieczeństwa do kolekcji, która diagnozuje względnie powszechny błąd programisty, pomyślałbym, że będą bardziej popularne. Z jakiegoś powodu we wszystkich dużych projektach Java, nad którymi pracowałem, nie widziałem ich już raz.Dlaczego Collection.checkedMap i znajomi nie są częściej używane?

Moje pytanie brzmi: czy istnieje szczególny powód, dla którego programiści Java częściej nie używają tych sprawdzonych opakowań? Czy jest to po prostu brak korzyści/braku wiedzy o ich istnieniu?

EDIT: Aby wyjaśnić moje pytanie, ogólne wersje kolekcji nadal zawierają niebezpieczne funkcje. , containsValue, remove i wszystkie działają na przykład na Object. Moje główne pytanie dotyczy tego, dlaczego więcej osób nie używa sprawdzonych implementacji do diagnozowania naruszeń typu środowiska wykonawczego.

Odpowiedz

13

Klasy te są naprawdę konieczne tylko wtedy, gdy ktoś nadużywa (lub nie stosuje) generyków. Powtarza się podczas sprawdzania w czasie wykonywania, które powinny być wystarczające do wykonania w czasie kompilacji dzięki gwarancjom bezpieczeństwa typu generic engine.

W związku z tym zastosowanie tych metod jest naprawdę interesujące tylko w kontekście projektantów interfejsów API, którzy nie ufają użytkownikom biblioteki i chcą chronić samych siebie lub użytkowników przed niewłaściwymi użytkownikami map. .

Oto krótka z nim: jeśli kod kompiluje bez surowych ostrzeżeń typu lub jakiekolwiek niekontrolowanych ostrzeżeń konwersja/typ, jesteś gwarantowana że metody checked* nie daje żadnych korzyści; są tylko trafieniem w czasie wykonywania.

Edit

Wydajesz się być stwierdzenie, że od remove, get itp działać na Object, są one jakoś wpisać-niebezpieczne. Oni nie są. Żadna z tych metod nie zapisuje swojego argumentu na mapie, więc z pewnością nie zagraża bezpieczeństwu typu samej mapy. Te metody pobierają obiekt z jednego głównego powodu: dla zgodności wstecznej. Nigdy nie było rygorystycznego wymogu, aby poszukiwacze musieli przestrzegać tej samej klasy. Na przykład, jeśli instancja klasy A i instancja klasy B mogą w jakiś sposób być sobie równe, umieszczając a na mapie, a następnie wywołując odwzorowanie .

To zachowanie musiało być obsługiwane po dodaniu generyków, aby zachować kompatybilność wsteczną. W związku z tym nie mogli zaktualizować interfejsu do czegoś podobnego do remove(K), ponieważ istniejący kod może polegać na możliwości usunięcia odwzorowania danego wystąpienia zupełnie innej klasy. Nie jest to jednak typ niebezpieczny, a użycie sprawdzonej wersji mapy nie zmienia tego zachowania w najmniejszym stopniu.

+0

Głównym powodem, dla którego może wydawać się dobrym pomysłem na posiadanie tych pojemników, jest na przykład funkcja .put() mapy, która pobiera obiekt, a nie K (na przykład na mapie ). To naprawdę nie wygląda na nadużycie generyków, aby przypadkowo dodać obiekt niewłaściwego typu do mapy; to bardziej błąd programisty. – templatetypedef

+2

@templatetypedef: Nie jestem pewien co masz na myśli. "Put" mapy jest określone jako 'put (K, V)'. Nie możesz umieścić żadnego starego obiektu w Mapie, jeśli używasz generycznych. –

+0

@ Mark Peters- Mój błąd; Miałem na myśli 'put', który przyjmuje' Object' zamiast 'K'. "remove" jest tą samą metodą, co 'containsKey' i' containsValue'. – templatetypedef

0

RETRACT: Poniższa opinia jest błędna. Istnieje kilka dobrych powodów, poza kompatybilnością wsteczną, dlaczego lepiej jest mieć indeks odnośników dowolnego typu.

Nie ma boskiego powodu, dla którego metody te muszą zająć Object zamiast E. W programach rzeczywistych, jeśli przekazany zostanie obiekt inny niż E, to prawie na pewno błąd aplikacji.W większości sytuacji API wersji E byłoby lepsze niż wersja Object. I mówię, że Sun popełnił tu błąd. Nie ma problemu z kompatybilnością wsteczną, ponieważ ogólny interfejs API to zupełnie nowy interfejs API.

Na szczęście mój IDE (IntelliJ) ostrzegłby mnie, gdybym przekazał te metody innym typom. Statyczne sprawdzanie zostało wypchnięte daleko poza to, co mówi specyfikacja języka i co robi kompilator.

+0

Nie wykonałem d/v, ale wystąpił problem kompatybilności wstecznej, a interfejsy API kolekcji generycznych nie były "zupełnie nowe", zmodernizowano istniejący interfejs API kolekcji. –

+0

@ mark-peters the put (K, V) również łamie twoją "kompatybilność wsteczną", ponieważ stara metoda nie ma ograniczenia. ale nie, nie ma takich problemów ze zgodnością, ponieważ każdy kod korzystający z interfejsu ogólnego jest nowym kodem i akceptuje nowe ograniczenia, a jeśli akceptują put (K, V), mogą zaakceptować remove (K). właściwie każdy chce usunąć (K) zamiast usunąć (obiekt). teraz odzyskaj mój punkt widzenia. – irreputable

+0

Nie chodzi o kompatybilność kodu źródłowego lub kodu bajtowego. Chodzi o kontrakt na 'remove (Object)' i podobne metody. Gdy dodawali kolekcje do generycznych, aby zaktualizować 'remove (Object)' do 'remove (K)' musieliby zmienić specyfikację metody (jak w tym, co robi * funkcjonalnie *). –