23.06.20235 min
Manoj Chemate

Manoj ChemateSoftware Engineer

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

Jeśli jesteś Junior Java Developerem, musisz zrozumieć pewne koncepty, aby nie popełniać błędów.

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,

  1. musisz nadpisać metodę hashcode w taki sposób, że jeśli metoda equals zwróci wartość true dla dwóch obiektów, to metoda hashcode musi zwrócić tę samą liczbę całkowitą dla tych obiektów.
  2. 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

  1. Jeśli spróbujesz dodać lub usunąć obiekty podczas iteracji używając iteratora techniki fail-fast, otrzymasz ConcurrentModificationException.
  2. Iterator typu fail-fast działa na oryginalnej kolekcji i używa wewnętrznej flagi modCount, aby sprawdzić, czy w kolekcji zaszły jakiekolwiek zmiany strukturalne. Jeśli tak, wykonanie nie powiedzie się.


Rozwiązanie:

  1. można użyć bezpiecznych dla wątków odpowiedników kolekcji java.util.concurrent.Copy OnWriteArrayList lub java.util.concurrent.CopyOnWriteArraySet, w których iterator używa kopii oryginalnej tablicy do przechodzenia i dokonuje modyfikacji oryginalnej tablicy.
  2. 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

  1. 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.
  2. 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

  1. Tutaj Arrays.asList() daje nam niezmienną listę, do której próbujemy dodać kolejną nazwę, dlatego otrzymamy tutaj UnsupportedOperationException.
  2. 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?

  1. Jeśli metoda stop( ) jest wykonywana przez inny wątek, możliwe, że wartość true zmiennej stop nigdy nie będzie widoczna dla MyThread, jeśli cache’ował on wartość zmiennej.
  2. 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?
  3. 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

  1. Tutaj bob i bobAgain odnoszą się do różnych obiektów na stosie, stąd porównanie referencji (==) zwróci false i zostanie wykonany blok else. Zwróci on wartość true tylko wtedy, gdy oba punkty odniesienia wskazują na ten sam obiekt w pamięci.
  2. metoda equals(other) sprawdza rzeczywistą zawartość obiektu. Oczywiście zależy to od sposobu nadpisania metody equals.


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.

<p>Loading...</p>