RU | EN | DE

1. var for Local Variables (Java 10)

Idea. The type is inferred from the right-hand side, except for uninitialized local variables.

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);
  }
}

Explanation. var doesn’t change the type, only makes the declaration shorter. Errors. var x; — not allowed without initialization. var in fields — not allowed. Best practices. Use it when the type is obvious from the RHS (new HashMap<>(), factories, stream operations).

2. Switch Expressions (Java 14 permanent; 12–13 preview)

Idea. switch returns a value, arrow functions ->, 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);
  }
}

Errors. Mixing old : and new -> in one block. Best. Prefer the arrow syntax, no fall-through and break.

3. Text Blocks """...""" (Java 15)

Idea. Multiline strings without escaping.

public class TextBlocksDemo {
  public static void main(String[] args) {
  String json = """
  {
  "name": "Vitaliy",
  "skills": ["Java","Spring"]
  }
  """;
  System.out.println(json);
  }

Errors. Extra indentation — align to the “common indentation” of the closing """. Best. For SQL/JSON/XML — readability + formatted(...) for substitutions.

4. Records (Java 16)

Idea. Compact immutable DTO: equals/hashCode/toString and accessors are generated.

public record User(String username, int level) {
  public User {
  if (level < 0) throw new IllegalArgumentException("level >= 0");
  }
  public String display() { return username + ":" + level; }
}

Errors. Mutation via reflection/non-standard tricks — breaks the idea of records. Best. Store “data without state”, validation — in the compact constructor.

5. Pattern Matching for instanceof (Java 16)

Idea. Pattern matching immediately gives you a variable of the correct type.

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;
}

Errors. Shadowing variables: don’t redefine the name s in the inner scope. Best. Remove casts: less noise and NPEs.

6. Sealed Classes/Interfaces (Java 17)

Idea. Limited polymorphism: who can inherit.

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 { // can inherit freely further
  public final double w, h;
  public Rect(double w, double h) { this.w = w; this.h = h; }
}

Errors. Forget permits (if not all in one file/package). Best. Combine with switch + patterns — exhaustive branches.

7. Pattern Matching for switch + Guarded Patterns (Java 21 permanent)

Idea. switch by types and conditions, exhaustive checks.

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";
};
}

Errors. Uncovered cases (add default/null). Best. For sealed hierarchies, default is often not needed — the compiler checks for completeness.

8. Record Patterns (Java 21 permanent)

Idea. Unpack record directly into variables/switch branches.

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;
};
}

Errors. Mismatch of arity/order of components. Best. Use together with sealed for clean pattern-based code.

9. Unnamed Variables & Patterns (_) (Java 22 permanent)

Idea. _ as “I consciously ignore”.

public class UnderscoreDemo {
public static void main(String[] _ /* ignores arguments */) {
Object o = "java";
if (o instanceof String _) { // matched, but value is not needed
System.out.println("It is String");
}
}

Errors. _ cannot be used as a regular variable name. Best. Mark “unused” parameters/patterns to avoid dummy variables.

10. Compact Source Files & Instance main (Java 25, final branch unnamed/implicit)

Idea. Mini-programs without an explicit class in the source; main is not static.

void main() { System.out.println("Hello, Java 25!"); }

The compiler automatically “wraps” it in a class during compilation.

Errors. Use both a regular class and a “compact” style in the same file. Best. Excellent for examples, tools, snippets.

11. Flexible Constructor Bodies (Java 25 permanent)

Idea. You can execute code before super(...)/this(...) (with restrictions on order and initialization).

class Base {
  Base(String id) { System.out.println("Base " + id); }
}
class Child extends Base {
  Child(String raw) {
String id = raw.trim().toUpperCase(); // logic before super(...)
super(id);
System.out.println("Child ready");
}
}

Errors. Referencing this/overridden methods before correct initialization — avoid side effects. Best. Keep early logic clean/deterministic (parsing, validation, normalization).

12. Module System (Java 9) — only language syntax

Idea. module-info.java describes the boundaries.

module com.example.core {
exports com.example.api;
requires java.sql;
}

Errors. “Grey” dependencies, forgotten exports. Best. Explicitly fix the public surface through exports/opens.

13. Module Import Declarations (Java 25 permanent)

Idea. Import the entire module “into the visibility space” of the source.

import module java.base;
import module java.sql;
public class ModuleImportDemo {
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();
}
}

Errors. Confusing with import package.*; — that’s a different mechanism (module level). Best. Use in modular applications for explicit dependencies in the sources.

14. Primitives in Patterns/instanceof/switch (Java 25 — still preview)

Idea. Match on primitives without boxing.

// Compile with --enable-preview --release 25
static String describeInt(int x) {
return switch (x) {
case int i && i > 0 -> "positive";
case 0 -> "zero";
default -> "negative";
};
}

Errors. Forget --enable-preview during compilation/run. Best. Experiment selectively; monitor finalization in 26+.

Common Migration Errors (8 → 25)

  • Confusing switch expression (needs a value) and the old switch (operator).
  • Using record as a “god object” with mutable fields via mutator tricks — breaks the contract.
  • sealed + switch: forgetting to add new subclasses — the compiler will complain about uncovered cases.
  • Text Blocks with a “ladder” of indentation — align the closing quotes.

Style Recommendations

  • Include pattern matching for branching by type/shape of data — fewer casts and if-else.
  • For DTOs — records; for hierarchies with a closed set — sealed.
  • For template text — text blocks; for computed text — switch expressions + formatted(...).
  • Demonstrate new learning/CLI snippets in the style of Compact Source Files (Java 25).