1. var для локальных переменных (Java 10)
Идея. Тип выводится из правой части, только для локальных неинициализированных нельзя.
public class VarDemo {
public static void main(String[] args) {
var list = java.util.List.of("a", "b"); // List<String>
for (var s : list) {
System.out.println(s.toUpperCase());
}
var map = new java.util.HashMap<String, Integer>();
map.put("x", 1);
}
}Пояснения. var не меняет тип, только делает запись короче.
Ошибки. var x; — нельзя без инициализации. var в полях — нельзя.
Best practices. Используй, когда тип очевиден из RHS (new HashMap<>(), фабрики, потоковые операции).
2. Switch-выражения (Java 14 permanent; 12–13 preview)
Идея. switch возвращает значение, стрелки ->, yield.
public class SwitchExprDemo {
enum Day { MON, SAT, SUN }
public static void main(String[] args) {
var d = Day.SAT;
int hours = switch (d) {
case SAT, SUN -> 0;
case MON -> 8;
default -> 6;
};
System.out.println(hours);
}
}Ошибки. Смешивать старый : и новый -> в одном блоке.
Best. Предпочитай «стрелочный» синтаксис, нет fall-through и break.
3. Text Blocks """...""" (Java 15)
Идея. Многострочные строки без экранирования.
public class TextBlocksDemo {
public static void main(String[] args) {
String json = """
{
"name": "Vitaliy",
"skills": ["Java","Spring"]
}
""";
System.out.println(json);
}
}Ошибки. Лишние отступы — ориентируйся на «общий отступ» закрывающих """.
Best. Для SQL/JSON/XML — читаемость + formatted(...) для подстановок.
4. Records (Java 16)
Идея. Компактные неизменяемые DTO: equals/hashCode/toString и аксессоры генерятся.
public record User(String username, int level) {
public User {
if (level < 0) throw new IllegalArgumentException("level >= 0");
}
public String display() { return username + ":" + level; }
}Ошибки. Мутация через отражение/нестандартные трюки — ломает идею records.
Best. Храни «данные без логики состояния», валидация — в компактном конструкторе.
5. Pattern matching для instanceof (Java 16)
Идея. Сопоставление с образцом сразу даёт переменную нужного типа.
static int len(Object o) {
if (o instanceof String s) return s.length();
if (o instanceof java.util.Collection<?> c) return c.size();
return -1;
}Ошибки. Тень переменных: не переопределяй имя s во вложенной области.
Best. Убирай касты: меньше шума и NPE.
6. Sealed classes/interfaces (Java 17)
Идея. Ограниченный полиморфизм: кто может наследоваться.
public sealed interface Shape permits Circle, Rect { }
public final class Circle implements Shape {
public final double r;
public Circle(double r) { this.r = r; }
}
public non-sealed class Rect implements Shape { // дальше можно наследовать свободно
public final double w, h;
public Rect(double w, double h) { this.w = w; this.h = h; }
}Ошибки. Забыть permits (если не все в одном файле/пакете).
Best. Комбинируй с switch + паттерны — исчерпывающие ветки.
7. Pattern matching для switch + Guarded patterns (Java 21 permanent)
Идея. switch по типам и условиям, исчерпывающие проверки.
static String render(Object o) {
return switch (o) {
case null -> "null";
case String s when s.isBlank() -> "empty string";
case String s -> "str: " + s;
case Integer i && i > 0 -> "pos int: " + i;
case java.util.List<?> lst -> "list size=" + lst.size();
default -> "other";
};
}Ошибки. Непокрытые варианты (добавляй default/null).
Best. Для sealed-иерархий default часто не нужен — компилятор следит за полнотой.
8. Record patterns (Java 21 permanent)
Идея. Распаковывать record прямо в переменные/ветки switch.
record Point(int x, int y) {}
static int manhattan(Object o) {
return switch (o) {
case Point(int x, int y) -> Math.abs(x) + Math.abs(y);
default -> -1;
};
}Ошибки. Несоответствие арности/порядка компонент.
Best. Используй вместе с sealed для чистого pattern-based кода.
9. Unnamed variables & patterns (_) (Java 22 permanent)
Идея. _ как «я осознанно игнорирую».
public class UnderscoreDemo {
public static void main(String[] _ /* игнор аргументов */) {
Object o = "java";
if (o instanceof String _) { // matched, но значение не нужно
System.out.println("It is String");
}
}
}Ошибки. _ нельзя использовать как обычное имя переменной.
Best. Помечай «неиспользуемые» параметры/паттерны, чтобы не плодить заглушки.
10. Compact Source Files & Instance main (Java 25, финал ветки unnamed/implicit)
Идея. Мини-программы без явного класса в исходнике; main — нестатический.
// File: Hello.java (Java 25)
void main() { System.out.println("Hello, Java 25!"); }Компилятор сам «оборачивает» в класс при сборке. Ошибки. Использовать одновременно обычный класс и «компактный» стиль в одном файле. Best. Отлично для примеров, тулзов, сниппетов.
11. Flexible Constructor Bodies (Java 25 permanent)
Идея. В конструкторах можно выполнять код до явного super(...)/this(...) (с ограничениями порядка и инициализации).
class Base {
Base(String id) { System.out.println("Base " + id); }
}
class Child extends Base {
Child(String raw) {
String id = raw.trim().toUpperCase(); // логика до super(...)
super(id);
System.out.println("Child ready");
}
}Ошибки. Обращение к this/переопределённым методам до корректной инициализации — избегай побочек.
Best. Держи раннюю логику чистой/детерминированной (парсинг, валидация, нормализация).
12. Module system (Java 9) — только синтаксис языка
Идея. module-info.java описывает границы.
module com.example.core {
exports com.example.api;
requires java.sql;
}Ошибки. «Серые» зависимости, забытый exports.
Best. Явно фиксируй публичную поверхность через exports/opens.
13. Module Import Declarations (Java 25 permanent)
Идея. Импорт всего модуля «в пространство видимости» исходника.
import module java.base;
import module java.sql;
public class ModuleImportDemo {
public static void main(String[] args) {
System.out.println(java.time.Instant.now());
try (var conn = java.sql.DriverManager.getConnection("jdbc:h2:mem:db")) {
System.out.println(conn.getMetaData().getURL());
} catch (Exception e) {
e.printStackTrace();
}
}
}Ошибки. Путать с import package.*; — это другая механика (уровень модуля).
Best. Используй в модульных приложениях для явности зависимостей в исходниках.
14. Примитивы в паттернах/instanceof/switch (Java 25 — всё ещё preview)
Идея. Матчить по примитивам без боксинга.
// Компилируй с --enable-preview --release 25
static String describeInt(int x) {
return switch (x) {
case int i && i > 0 -> "positive";
case 0 -> "zero";
default -> "negative";
};
}Ошибки. Забыть --enable-preview во время компиляции/запуска.
Best. Пока экспериментируй точечно; следи за финализацией в 26+.
Частые ошибки миграции (8 → 25)
- Путают switch-выражение (нужно значение) и старый
switch(оператор). - Используют
recordкак «бог-объект» с изменяемыми полями через мутаторные трюки — ломает контракт. sealed+switch: забывают добавить новые подклассы — компилятор начнёт ругаться на неохваченность.- Text Blocks с «лесенкой» отступов — выровняй закрывающие кавычки.
Рекомендации по стилю
- Включай pattern matching для ветвления по типу/форме данных — меньше кастов и
if-else. - Для DTO — records; для иерархий с закрытым набором — sealed.
- Для шаблонного текста — text blocks; для вычисляемого текста — switch-выражения +
formatted(...). - Новые учебные/CLI-сниппеты демонстрируй в стиле Compact Source Files (Java 25).