7 błędów popełnianych przez początkujących programistów Javy!

Jeśli Java to dla Ciebie coś nowego, to ten artykuł pomoże Ci lepiej zrozumieć pewne niejasne koncepty.
1. Ignorowanie przekazywania przez wartość w Javie
Czy zauważyłeś tutaj błąd?

Tutaj, person nie będzie wartością null, ponieważ Java jest przekazywana przez wartość, a nie przez referencję. Co to oznacza?
Można wyróżnić tutaj trzy części, rzeczywisty obiekt person jest tworzony na stosie, następnie referencja, która wskazuje na ten właśnie obiekt person na stosie, a sama referencja ma wartość, która reprezentuje położenie obiektu na stosie, bob to referencja, która wskazuje na obiekt person na stosie, a bob jako referencja ma również pewną wartość reprezentującą położenie obiektu (to jeszcze nie jest dokładny adres).
Tak więc, gdy bob jest przekazywany jako parametr do metody makeItNull(), wartość referencji bob jest kopiowana do referencji bob1, a nie do rzeczywistego obiektu stosu. Gdy bob1 jest przypisywany do wartości null, wartość referencji bob1 to null, ale wartość oryginalnej referencji bob nie zmienia się.
Podczas przekazywania prymitywnych danych, JVM kopiuje wartość prymitywnego typu danych. Jeśli int x=5, to skopiowane zostanie samo 5.
Podczas przekazywania obiektu, wartość referencji jest kopiowana do innej zmiennej, a nie do rzeczywistego obiektu.
I dlatego Java jest uważana za pass-by-value, a nie pass-by-reference.
W językach typu pass-by-reference oryginalny bob miałby wartość null.
2. Łamanie kontraktu Hashcode-Equals
Czego tu brakuje?

Jeśli nie nadpiszesz metody hashcode-equals w klasie Person, Bob nie będzie tam obecny, nawet jeśli z biznesowego punktu widzenia są to te same obiekty. Dlaczego? HashMap, HashSet i Hashtable identyfikują zduplikowane klucze za pomocą metod hashcode i equals.
Podczas przechowywania obiektów, liczba całkowita kodu skrótu jest obliczana za pomocą metody hashcode, a jeśli mapa zawiera już ten kod skrótu, wówczas metoda equals zostanie wywołana w celu sprawdzenia, czy obiekty są rzeczywiście takie same, a jeśli są takie same, wówczas wartości zostaną zastąpione.
Podobnie podczas pobierania obiektów, jeśli hashcode() jest taki sam, wywoływana jest metoda equals( ) w celu sprawdzenia, czy jest to ten sam klucz, a jeśli tak, zwracana jest wartość.
Tutaj, podczas przechowywania obiektów, ponieważ metoda hashcode() i equals() nie jest nadpisana, zostanie wywołana metoda hashcode i equals klasy Object
Metoda hashcode klasy Object zwraca inną wartość dla każdego nowego obiektu w JVM.
Metoda equal klasy Object porównuje referencje.
Tak więc kod skrótu dla bob i bob1 będzie inny. Hash bob1 nie będzie obecny na mapie.
Pamiętaj o prostym kontrakcie:
Jeśli metoda equals jest nadpisana w jakiejś klasie,
- musisz nadpisać metodę
hashcodew taki sposób, że jeśli metodaequalszwróci wartośćtruedla dwóch obiektów, to metodahashcodemusi zwrócić tę samą liczbę całkowitą dla tych obiektów. - jeśli obiekty nie są takie same za pomocą metody
equals, to mogą, ale nie muszą zwrócić ten sam kod skrótu.
Nawet jeśli nadpisałeś hashcode-equals, nie jest dobrą praktyką używanie zmiennych obiektów jako kluczy, ponieważ później, jeśli klucze zostaną zmodyfikowane, nie będzie można ich odzyskać, ponieważ hashcode-equals zmieni wyniki z powodu modyfikacji.
3. Modyfikowanie kolekcji podczas iteracji

- Jeśli spróbujesz dodać lub usunąć obiekty podczas iteracji używając iteratora techniki fail-fast, otrzymasz
ConcurrentModificationException. - Iterator typu
fail-fastdziała na oryginalnej kolekcji i używa wewnętrznej flagimodCount, aby sprawdzić, czy w kolekcji zaszły jakiekolwiek zmiany strukturalne. Jeśli tak, wykonanie nie powiedzie się.
Rozwiązanie:
- można użyć bezpiecznych dla wątków odpowiedników kolekcji j
ava.util.concurrent.Copy OnWriteArrayListlubjava.util.concurrent.CopyOnWriteArraySet, w których iterator używa kopii oryginalnej tablicy do przechodzenia i dokonuje modyfikacji oryginalnej tablicy. - Można również użyć
ConcurrentHashMap, chociaż nie używa ona kopii oryginalnej kolekcji do przechodzenia. Nie posiada implementacji typu fail-fast.

4. Niezamykanie zasobów systemowych
- Aplikacja Javy wykorzystuje kilka rodzajów zasobów, takich jak pliki, strumienie, porty i połączenia z bazami danych. Musimy zadbać o to, by były one udostępniane nawet w przypadku błędów.
- Ponieważ każda aplikacja ma ograniczoną liczbę przypisanych zasobów, ich nadużywanie prowadzi do wielokrotnego ponownego uruchamiania aplikacji i wpływania na inne aplikacje w tym samym środowisku.
Jak zamknąć zasoby?
Możesz użyć bloku finally lub bloku try-with-resource wprowadzonego w Javie 7. Podczas korzystania z try-with-resource można zadeklarować wiele zasobów, a każdy zasób musi implementować interfejs java.io.AutoCloseable, który ma metodę close() określającą sposób zamykania zasobów. Metoda ta będzie zawsze wywoływana przez JVM po pomyślnym zakończeniu bloku try lub po wystąpieniu wyjątku.

5. Modyfikowanie niezmiennych obiektów

- Tutaj
Arrays.asList()daje nam niezmienną listę, do której próbujemy dodać kolejną nazwę, dlatego otrzymamy tutajUnsupportedOperationException. - Stan niezmiennych obiektów nie może i nie powinien być zmieniany. Jeśli jest to wymagane, sam obiekt nie powinien być niezmienny.
6. Widoczność zmiennej w środowisku wielowątkowym
Czy uważasz, że MyThread zawsze będzie w tym miejscu?

- Jeśli metoda
stop( )jest wykonywana przez inny wątek, możliwe, że wartośćtruezmiennej stop nigdy nie będzie widoczna dlaMyThread, jeśli cache’ował on wartość zmiennej. - Jeśli zmienna jest współdzielona przez wiele wątków, zmiany wprowadzone przez jeden wątek mogą, ale nie muszą być widoczne dla drugiego wątku. Dlaczego?
- Gdy wątek próbuje zmodyfikować wartość zmiennej, w zależności od architektury procesora, wartość zmiennej może zostać skopiowana do lokalnej pamięci podręcznej rdzenia procesora zamiast zawsze odczytywać ją z pamięci głównej w celu zwiększenia wydajności, co nie będzie widoczne dla innego wątku pracującego nad nią w tym samym czasie.
Rozwiązanie:
Użycie modyfikatora volatile gwarantuje więc, że wątki zawsze będą widzieć zaktualizowane wartości.

7. Używanie == zamiast equals do porównywania obiektów

- Tutaj
bobibobAgainodnoszą się do różnych obiektów na stosie, stąd porównanie referencji(==)zwrócifalsei zostanie wykonany blokelse. Zwróci on wartość true tylko wtedy, gdy oba punkty odniesienia wskazują na ten sam obiekt w pamięci. - metoda
equals(other)sprawdza rzeczywistą zawartość obiektu. Oczywiście zależy to od sposobu nadpisania metodyequals.

Wyliczenia są domyślnie singleton w Javie, więc wszystkie odniesienia do tego samego wyliczenia będą wskazywać na ten sam obiekt, a zatem porównanie referencyjne działa dla wyliczeń.

w takim więc przypadku blok If zostanie wykonany
To już chyba wszystko. Jeśli podobał Ci się artykuł, zaobserwuj mnie po więcej treści! I koniecznie sprawdź mój artykuł na temat Java Streams!
Dzięki!
Oryginał tekstu w języku angielskim przeczytasz tutaj.