Java 10: korzystanie ze zmiennych lokalnych var

developeronthego.pl 2 lat temu
Zdjęcie: java 10


%title%

W kolejnej odsłonie języka Java nie dostaniemy wiele ciekawych featurów. Java 10 to po prostu kolejny update do JDK i nie nanosi na język rewolucyjnych zmian. Mimo wszystko choćby w tej wersji pojawiła się jedna interesująca aktualizacja, dotycząca zmiennych lokalnych, którą z pewnością będziesz wykorzystywać w swoim kodzie.

Zmiany w Java 10
  • Rozszerzone wnioskowanie typów i var
  • Optymalizacja JVM
  • Optional*.orElseThrow()
  • Zmiany w kolekcjach niemodyfikowalnych
  • Podsumowanie zmian w Java 10

Rozszerzone wnioskowanie typów i var

Korzystanie z wnioskowanych typów było już dawno zaimplementowane w konkurencyjnym języku C#. Nie jest to jednak to samo, co dynamicznie typowanie, takie jakie zachodzi w językach: PHP, Javascript, czy Python. Dynamiczne typowanie pozwala na korzystanie ze zmiennych, tak jakby ich typ nie miałby znaczenia. Typ jest sprawdzany (i jeżeli trzeba rzutowany) w momencie użycia (czyli tzw. runtime). W przeciwieństwie do dynamicznych typów, statyczne typowanie jest już sprawdzane, gdy kompilujesz program. Pozwala to na uniknięcie wielu prostych błędów już we wczesnym etapie tworzenia oprogramowania.

Tak naprawdę nowe słowo najważniejsze var, to po prostu skrócony zapis, pod którym kryje się konkretny typ zmiennej lokalnej. Przykładem niech będzie zdefiniowanie zmiennej typu prostego (np. int).

var value = 10;

Do Java 10 programista musiał skorzystać z konkretnego typu zmiennej (czyli w tym przypadku byłoby to: int value = 10;). Podobnie można tworzyć nie tylko zmienne typów prymitywnych, ale też referencyjnych.

var text = "hello!"

W powyższym przykładzie użyłem var zamiast typu String, który jest obiektem. Var możesz też używać w przypadku wszelkich struktur danych (takich jak np. List czy Map).

var list = List.of("ala", "ma", "kota", value, text);

Możesz wykorzystać statyczne typowanie także w pętlach for-each.

for (var element : list) { System.out.println(element); }

Skoro var działa w pętli for-each, to dlaczego nie skorzystać z niego w klasycznej pętli for.

for (var i = 0; i < list.size(); i++) { System.out.println(list.get(i)); }

Ostatnim ciekawym przypadkiem jest użycie var w implementacji try – with resources.

try (var bufferedReader = new BufferedReader(new FileReader("myapp-log.txt"))) { /* some business logic */ } catch (IOException e) { /* some logger */ }

Kiedy jednak nie da się skorzystać z słowa kluczego var? Var nie zadziała w przypadku:

  • zmiennych klasowych
  • zmiennych lokalnych z przypisanym nullem
  • zmiennych lokalnych, których przypisanie wartości nie nastąpiło w miejscu ich deklaracji
  • przypisaniu wartości o innym typie niż ten, który został użyty we wcześniej zdefiniowanej zmiennej (nawet jeżeli oba typy będą implementowały ten sam interfejs)
  • sygnaturach metod w miejscach, gdzie definiujesz parametry czy typ zwracany

Optymalizacja JVM

Konteneryzacja (np. dzięki Dockera) w momencie wydawania Java 10 (marzec 2018) stawała się już pomału standardem. Dlatego też JVM w wersji 10, które są uruchamiane dzięki kontenera Dockera*, mogą skorzystać ze specjalnej flagi -XX:-UseContainerSupport, która ułatwia dostarczanie informacji o zasobach przypisanych przez system do kontenera. Kolejną ciekawą zmianą jest możliwość odpytywanie wątków (ang. Thread-Local Handshakes) dzięki tzw. wywołania zwrotnego (ang. callback). Idea jest taka, iż zamiast czekać na globalny bezpieczny punkt, aby zatrzymać wszystkie wątki, używa się wywołania zwrotnego, aby wpłynąć na poszczególne wątki. Flaga JVM odpowiedzialna za tą zmianę to: -XX:ThreadLocalHandshakes.

Optional*.orElseThrow()

Od Java 10 dodano nową operację orElseThrow do strumieni, którą możesz wykorzystać w miejscach, gdy szukasz co najmniej jednej wartości w jakimś ciągu elementów.

List<Integer> oddNumbers = List.of(1, 3, 5, 7, 13); Integer firstOddNumber = oddNumbers.stream() .filter(i -> i % 2 == 0) .findFirst() .orElseThrow();

W przypadku, gdy tak zaimplementowany strumień nie znajdzie żadnej pasującej wartości, to wyrzuci java.util.NoSuchElementException: No value present,

Zmiany w kolekcjach niemodyfikowalnych

Czasami potrzebujesz gwałtownie stworzyć niemodyfikowalną kopię swojej kolekcji danych. W Java 10 z pomocą przychodzi nowa metoda dostępna w kolekcjach copyOf, która wykona całą pracę za Ciebie.

List<Integer> fibonacci = List.of(1, 1, 2, 3, 5, 8, 13); List<Integer> copyList = List.copyOf(fibonacci); copyList.add(21); // throws exception

Podobne działanie, ale w przypadku strumieni, ma nowe kolektory, które zwracają kolekcje niemodyfikowalne (np. toUnmodifiableList).

List<Integer> filteredList = fibonacci.stream() .filter(i -> i % 2 == 0) .collect(Collectors.toUnmodifiableList()); filteredList.add(21); // throws exception

Oczywiście w obu przypadkach nowo utworzone kolekcje niemodyfikowalne w przypadku ich edycji, zwrócą wyjątek java.lang.UnsupportedOperationException.

Podsumowanie zmian w Java 10

W nowym JDK 10 nie ujrzymy wielu ciekawych zmian. Wynika to z nowej polityki Oracle, zgodnie z którą co sześć miesięcy ma się pojawiać nowa wersja JDK. Oracle twierdzi, iż jest to odpowiedź na potrzebę ciągłej aktualizacji języka Java i podążaniem za najnowszymi trendami. Smutna prawda jest jednak taka, iż jest to świetny sposób na zwiększenie dochodów z różnego rodzaju szkoleń oraz certyfikatów, które są jednym z głównych dochodów firmy Oracle jako właściciela języka Java. Nas, programistów, powinny najbardziej interesować wersje LTS (ang. Long Term Support). JDK oznaczonej tym opisem będzie wspierana przez Oracle przez dłuższy czas, co w praktyce oznacza, iż w swojej nauce powinieneś się skupić właśnie na tych wersjach.

W kolejnej notce będę omawiał zmiany w JDK 11, która właśnie jest oznaczona jako wersja LTS.

Kod do lekcji: https://github.com/developeronthego/java9-plus/tree/main/src/main/java/jdk/java10/features

Idź do oryginalnego materiału