Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Современная Java: от 8 к 25

Новая версия Java выходит каждые полгода, а раз в два года одна из них получает долгую поддержку — LTS (long-term support). Это версии 8, 11, 17, 21 и 25. Многие проекты и статьи в интернете до сих пор написаны на Java 8, и современный код выглядит заметно иначе. В этом уроке собраны главные изменения со ссылками на уроки, где они разобраны подробно.

Java 8: основа

Java 8 (2014) — самая важная версия за всю историю языка. В ней появились:

Всё это — обычная часть современного кода, а не «новинки».

Java 9–11: меньше шаблонного кода

void main() {
    var names = List.of("Анна", "Олег");
    IO.println(names);
    IO.println("ab".repeat(3));
}

Результат:

[Анна, Олег]
ababab

Java 12–17: новые формы данных

Java 18–21: сопоставление с образцом и виртуальные потоки

void main() {
    List<String> queue = List.of("Анна", "Олег", "Ира");
 
    IO.println(queue.getFirst());
    IO.println(queue.getLast());
    IO.println(queue.reversed());
}

Результат:

Анна
Ира
[Ира, Олег, Анна]

Раньше для последнего элемента писали list.get(list.size() - 1).

Java 22–25: проще начать

  • Безымянная переменная _ для ненужных значений (Java 22) — Шаблоны записей.
  • Компактные файлы и метод main без static и параметров, класс IO для ввода и вывода, автоматический импорт пакетов java.base (Java 25) — Первая программа.
  • Код до вызова super(...) в конструкторе — например, проверка аргументов (Java 25).
  • Ограниченные значения ScopedValue — замена ThreadLocal для виртуальных потоков (Java 25) — Ограниченные значения.

Было и стало

Одна и та же задача — посчитать сумму заказов по покупателям — в стиле Java 8 и в стиле Java 25. Сначала старый вариант:

import java.util.*;
 
public class Main {
    static class Order {
        private final String customer;
        private final int amount;
 
        Order(String customer, int amount) {
            this.customer = customer;
            this.amount = amount;
        }
 
        String getCustomer() { return customer; }
        int getAmount() { return amount; }
    }
 
    public static void main(String[] args) {
        List<Order> orders = Arrays.asList(new Order("Анна", 20), new Order("Олег", 35), new Order("Анна", 15));
        Map<String, Integer> totals = new TreeMap<>();
        for (Order order : orders) {
            Integer current = totals.get(order.getCustomer());
            totals.put(order.getCustomer(), (current == null ? 0 : current) + order.getAmount());
        }
        System.out.println(totals);
    }
}

Результат:

{Анна=35, Олег=35}

Теперь современный — запись вместо класса, List.of, поток с группировкой и компактный файл:

record Order(String customer, int amount) {}
 
void main() {
    var orders = List.of(new Order("Анна", 20), new Order("Олег", 35), new Order("Анна", 15));
 
    var totals = orders.stream()
            .collect(Collectors.groupingBy(Order::customer, TreeMap::new, Collectors.summingInt(Order::amount)));
 
    IO.println(totals);
}

Результат:

{Анна=35, Олег=35}

Оба варианта работают в Java 25, но второй короче втрое и читается как описание задачи.

Частая ошибка

var не делает Java динамическим языком: тип переменной выводится один раз из начального значения и дальше не меняется:

void main() {
    var count = 10;
    count = "десять";
}

Результат:

Main.java:3: error: incompatible types: String cannot be converted to int
    count = "десять";
            ^
1 error
error: compilation failed

И помните, что новые возможности требуют новой версии: если проект собирается для Java 17, записи в нём есть, а шаблоны записей и компактные файлы — уже нет. Версию задают в настройках сборки, например <maven.compiler.release>25</maven.compiler.release> в Maven.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.