Skip to main content

Command Palette

Search for a command to run...

Java 17 Features Every Senior Developer Should Know - Part 6: Syntax Cheat Sheet & Reference Guide

Updated
10 min read
Java 17 Features Every Senior Developer Should Know - Part 6: Syntax Cheat Sheet & Reference Guide
D

I am a programmer who specializes in Java and Scala programming. My specialization is in the creation of telecommunication services for IMS networks using Java, Jain Slee specification, and SIP technology. My interest lies in Swift programming and Cloud technology, specifically designing cloud-based services using micro services and the JVM platform. Astronomy, martial arts, and strategic games are things I enjoy in my free time.

Complete Reference for Desktop | Print-friendly version for desk reference

This is Part 6 (final) of "Java 17 Features Every Senior Developer Should Know" - a comprehensive reference covering syntax, usage patterns, feature interactions, and migration strategies for all 6 features covered in Parts 1-5. Perfect for printing and keeping at your desk as you work with modern Java code.

How to Use This Series

First time learning Java 17 features?

Need a quick reference?

  • Use the Quick Reference Cards below (this page)

  • Each section provides syntax, examples, and use cases at a glance

  • Links to full parts for detailed explanations

Looking for specific feature?

  • Use the Table of Contents below to jump to any feature

  • Each Quick Reference Card links back to its full part

Want to understand feature interactions?

  • See full articles for detailed explanations and real-world patterns

Planning a migration?

  • See full articles for phased migration strategy and compatibility notes

Series Overview & Timeline

This series covers 6 major Java features spanning Java 10-17, representing over 20 years of language evolution:

PartFeatureReleaseJEP
1var - Local variable type inferenceJava 10286
2Records - Immutable data carriersJava 16395
3Sealed Classes - Controlled inheritanceJava 17409
4Pattern Matching - Type check + castJava 16394
5Switch Expressions - Returns valuesJava 14361
6Text Blocks - Multi-line stringsJava 15378

Why These Features Matter:

  • Part 1-2: Reduce boilerplate (less code to write)

  • Part 3-4: Increase safety (compiler catches more errors)

  • Part 5-6: Improve readability (code matches intent)


Feature Comparison Matrix

Decision At-a-Glance

ChallengeSolutionWhenAvoid
Long generic typesvarType obvious from right sideType unclear from context
Immutable data classesRecordsDTOs, value objectsMutable data, need inheritance
Controlled inheritanceSealed classesFixed type hierarchiesOpen-for-extension APIs
Type checking + castingPattern matchingChecking types with immediate usePolymorphism is better choice
Returning from switchSwitch expressionsEnum mapping, value computationSimple if-else, need fall-through
Multi-line stringsText blocksJSON, SQL, HTML, XMLSingle line strings

Feature Dependencies

var (Java 10)
    ↓ (enables clean declaration of)
Records (Java 16)
    ↓ (work well with)
Sealed Classes (Java 17)
    ↓ (enables exhaustive checking with)
Pattern Matching (Java 16)
    ↓ (used in)
Switch Expressions (Java 14)
    ↓ (format data with)
Text Blocks (Java 15)

Quick Reference Cards

var Keyword (Java 10)

JEP 286 | Local variable type inference

📖 See also: Part 1: Introduction & var Keyword - Full feature deep dive with examples and pitfalls

Syntax

var name = expression;

✅ Use When

  • Type is obvious from right side: var user = new User()

  • Long generic types: var map = new HashMap<String, List<Employee>>()

  • Stream chains: var filtered = list.stream().filter(...)

  • For-loops: for (var item : items)

❌ Don't Use When

  • Type isn't clear: var data = fetchData() (what type?)

  • Need supertype: List<String> list = new ArrayList<>() (flexibility)

  • Fields, parameters, return types (not allowed)

  • Lambda/method reference alone: var c = String::length (error)

Examples

// ✅ Good
var message = "Hello";
var count = 42;
var users = List.of("Alice", "Bob");
var map = new HashMap<String, Integer>();

// ❌ Bad
var x = getData();           // unclear type
var y = null;                // error: cannot infer
var list = new ArrayList<>(); // error: need type args

Quick Rules

  • Compile-time type inference (NOT dynamic typing)

  • Local variables only

  • Must have initializer

  • Type never changes


Records (Java 16)

JEP 395 | Immutable data carriers

📖 See also: Part 2: Records - Full feature deep dive with examples and best practices

Syntax

record Name(Type1 field1, Type2 field2) {
    // optional: custom methods, validation
}

✅ Use When

  • Data Transfer Objects (DTOs)

  • Value objects (Point, Money, Range)

  • Configuration objects

  • API request/response models

  • Return values from methods (multiple values)

❌ Don't Use When

  • Need mutability

  • Need inheritance (records are final)

  • Want to hide internal structure

  • Need JavaBeans getters (use field() not getField())

  • Complex lazy initialization

Examples

// Basic record
record Point(int x, int y) {}

// With validation (compact constructor)
record Range(int start, int end) {
    public Range {
        if (start > end) throw new IllegalArgumentException();
    }
}

// With custom methods
record Person(String name, int age) {
    public boolean isAdult() { return age >= 18; }
    public Person withAge(int newAge) { return new Person(name, newAge); }
}

// Generic record
record Pair<T, U>(T first, U second) {}

// Implementing interface
record Circle(double radius) implements Shape {
    @Override
    public double area() { return Math.PI * radius * radius; }
}

What You Get Automatically

  • Constructor: public Point(int x, int y)

  • Accessors: p.x(), p.y() (NOT getX(), getY())

  • equals(), hashCode(), toString()

  • Fields are private final

  • Class is final

Quick Rules

  • Immutable by default

  • All fields final

  • Cannot extend other classes

  • Can implement interfaces

  • Defensive copying needed for mutable components


Sealed Classes (Java 17)

JEP 409 | Controlled inheritance

📖 See also: Part 3: Sealed Classes - Design patterns and hierarchy control explained

Syntax

sealed interface/class Name permits SubType1, SubType2 {
}

// Subtypes must be: final, sealed, or non-sealed

✅ Use When

  • Closed type hierarchies (known subtypes only)

  • Domain modeling with fixed alternatives

  • Exhaustive pattern matching

  • API design where you control all implementations

❌ Don't Use When

  • Open for extension (third-party implementations)

  • Plugin architectures

  • Need unlimited subclassing

Examples

// Sealed interface with records
sealed interface Shape permits Circle, Rectangle, Triangle {}

record Circle(double radius) implements Shape {}
record Rectangle(double width, double height) implements Shape {}
record Triangle(double base, double height) implements Shape {}

// Sealed class hierarchy
sealed class Result<T> permits Success, Failure {}

final class Success<T> extends Result<T> {
    private final T value;
    // ...
}

final class Failure<T> extends Result<T> {
    private final String error;
    // ...
}

// With non-sealed for extension point
sealed interface Payment permits CreditCard, DebitCard, ExtensiblePayment {}
final class CreditCard implements Payment {}
final class DebitCard implements Payment {}
non-sealed interface ExtensiblePayment extends Payment {} // Open for extension

Permitted Subtypes Must

  • Be in same module (or same package if unnamed module)

  • Directly extend/implement the sealed type

  • Be declared as: final, sealed, or non-sealed

Quick Rules

  • Compiler knows all subtypes

  • Enables exhaustive pattern matching

  • Subtypes must be declared in permits clause

  • Better than marker interfaces for closed sets


Pattern Matching (Java 16)

JEP 394 | Pattern matching for instanceof

📖 See also: Part 4: Pattern Matching & Switch Expressions - Type patterns and exhaustiveness checking

Syntax

if (obj instanceof Type variableName) {
    // use variableName here
}

✅ Use When

  • Type checking with immediate use

  • Implementing equals() methods

  • Polymorphic dispatch

  • Guard conditions: obj instanceof String s && s.length() > 5

❌ Don't Use When

  • Polymorphism would be better (add methods to types)

  • Type checking indicates design smell

  • Performance is absolutely critical

Examples

// Basic pattern matching
if (obj instanceof String s) {
    System.out.println(s.toUpperCase());
}

// With guards
if (obj instanceof String s && s.length() > 0) {
    return s.toUpperCase();
}

// Simplified equals()
@Override
public boolean equals(Object obj) {
    return obj instanceof Point p && this.x == p.x && this.y == p.y;
}

// Type hierarchy
if (shape instanceof Circle c) {
    return Math.PI * c.radius() * c.radius();
} else if (shape instanceof Rectangle r) {
    return r.width() * r.height();
}

Scope Rules

if (obj instanceof String s && s.length() > 5) {
    // 's' in scope here
}

if (!(obj instanceof String s)) {
    // 's' NOT in scope
} else {
    // 's' IS in scope here
}

Quick Rules

  • Pattern variable scoped by flow analysis

  • instanceof returns false for null (safe)

  • No manual cast needed

  • Combines type check + cast + assignment


Switch Expressions (Java 14)

JEP 361 | Switch as expression with arrow syntax

📖 See also: Part 4: Pattern Matching & Switch Expressions - Clean conditional logic with yield

Syntax

// Arrow syntax (no fall-through)
var result = switch (value) {
    case LABEL1 -> expression1;
    case LABEL2, LABEL3 -> expression2;
    default -> expressionN;
};

// Multi-statement with yield
var result = switch (value) {
    case LABEL1 -> {
        // statements
        yield value1;
    }
};

✅ Use When

  • Mapping enum values

  • Returning values from branches

  • Exhaustive enum matching (no default needed)

  • Multi-way conditional logic

❌ Don't Use When

  • Simple if-else would suffice

  • Need fall-through (use colon syntax)

  • Cases are complex and unrelated

Examples

// Basic switch expression
String dayType = switch (day) {
    case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "Weekday";
    case SATURDAY, SUNDAY -> "Weekend";
};

// With yield
int result = switch (op) {
    case ADD -> {
        System.out.println("Adding");
        yield a + b;
    }
    case SUBTRACT -> {
        System.out.println("Subtracting");
        yield a - b;
    }
    default -> throw new IllegalArgumentException();
};

// Exhaustive enum (no default needed)
int days = switch (season) {
    case SPRING, SUMMER, FALL, WINTER -> 3;
};

Quick Rules

  • Arrow -> prevents fall-through

  • Must be exhaustive (all cases or default)

  • Use yield for multi-statement branches

  • No break needed with arrows

  • Can mix with pattern matching (future Java)


Text Blocks (Java 15)

JEP 378 | Multi-line string literals

📖 See also: Part 5: Text Blocks - Multi-line strings with security considerations

Syntax

String text = """
    content here
    more content
    """;

✅ Use When

  • Multi-line strings (JSON, SQL, HTML, XML)

  • Embedded code snippets

  • Long error messages

  • Test fixtures

❌ Don't Use When

  • Single-line strings

  • Dynamically built strings

  • Need platform-specific line endings

Examples

// JSON
String json = """
    {
      "name": "Alice",
      "age": 30,
      "email": "alice@example.com"
    }""";

// SQL
String sql = """
    SELECT u.name, u.email, o.total
    FROM users u
    JOIN orders o ON u.id = o.user_id
    WHERE o.status = 'COMPLETED'
    ORDER BY o.created_at DESC""";

// With formatted()
String json = """
    {
      "name": "%s",
      "age": %d
    }""".formatted(name, age);

// Indentation control
String text = """
    Line 1
        Indented line 2
    Line 3
    """;  // Closing delimiter determines indent stripping

// Line continuation
String long = """
    This is a long line that \
    continues on the next line \
    in source code.
    """;

// Essential space
String trailing = """
    Line with space:\s
    """;

Special Escapes

  • \s - Essential space (survives whitespace stripping)

  • \ - Line continuation (no newline inserted)

  • Standard escapes work: \n, \t, \", \\

Quick Rules

  • Opening """ must be followed by newline

  • Closing """ position determines indent

  • All line endings normalized to \n

  • Trailing whitespace auto-removed

  • Common indent automatically stripped


End of Series

This concludes "Java 17 Features Every Senior Developer Should Know"


Series Navigation