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

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?
Read Part 1: var Keyword → Part 2: Records → Part 3: Sealed Classes → Part 4: Pattern Matching → Part 5: Text Blocks
Each part includes practical examples and best practices
Estimated reading time: 1-2 hours total
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:
| Part | Feature | Release | JEP |
| 1 | var - Local variable type inference | Java 10 | 286 |
| 2 | Records - Immutable data carriers | Java 16 | 395 |
| 3 | Sealed Classes - Controlled inheritance | Java 17 | 409 |
| 4 | Pattern Matching - Type check + cast | Java 16 | 394 |
| 5 | Switch Expressions - Returns values | Java 14 | 361 |
| 6 | Text Blocks - Multi-line strings | Java 15 | 378 |
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
| Challenge | Solution | When | Avoid |
| Long generic types | var | Type obvious from right side | Type unclear from context |
| Immutable data classes | Records | DTOs, value objects | Mutable data, need inheritance |
| Controlled inheritance | Sealed classes | Fixed type hierarchies | Open-for-extension APIs |
| Type checking + casting | Pattern matching | Checking types with immediate use | Polymorphism is better choice |
| Returning from switch | Switch expressions | Enum mapping, value computation | Simple if-else, need fall-through |
| Multi-line strings | Text blocks | JSON, SQL, HTML, XML | Single 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()notgetField())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 finalClass 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, ornon-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()methodsPolymorphic 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-throughMust be exhaustive (all cases or default)
Use
yieldfor multi-statement branchesNo
breakneeded with arrowsCan 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 newlineClosing
"""position determines indentAll line endings normalized to
\nTrailing whitespace auto-removed
Common indent automatically stripped
End of Series
This concludes "Java 17 Features Every Senior Developer Should Know"
Part 1: var Keyword
Part 2: Records
Part 3: Sealed Classes
Part 5: Text Blocks
Part 6: Syntax Cheat Sheet (this document)
Series Navigation
← Part 5: Text Blocks - Multi-line string literals
← Series Overview - Overview and series guide



