Modern Java Features
Lambda Expressions
Basic Syntax
// Single parameter (parentheses optional)
x -> x * 2
// Multiple parameters
(x, y) -> x + y
// No parameters
() -> System.out.println("Hello")
// Block body with return
(x, y) -> {
int sum = x + y;
return sum * 2;
}
Functional Interfaces
// Using with Runnable
Runnable task = () -> System.out.println("Running");
new Thread(task).start();
// Comparator
Comparator<String> byLength = (a, b) -> a.length() - b.length();
list.sort(byLength);
// Custom functional interface
interface Calculator {
int calculate(int a, int b);
}
Calculator add = (a, b) -> a + b;
Calculator multiply = (a, b) -> a * b;
Variable Capture
int factor = 10;
Function<Integer, Integer> multiplier = x -> x * factor;
// factor must be effectively final
Method References
Types of Method References
| Type | Syntax | Example |
| Static method | ClassName::staticMethod | Integer::parseInt |
| Instance method (bound) | instance::method | str::length |
| Instance method (unbound) | ClassName::method | String::toLowerCase |
| Constructor | ClassName::new | ArrayList::new |
Examples
// Static method reference
list.forEach(System.out::println);
// Instance method on specific object
String prefix = "Hello, ";
names.stream().map(prefix::concat).forEach(System.out::println);
// Instance method on parameter
names.stream().map(String::toUpperCase).forEach(System.out::println);
// Constructor reference
Supplier<List<String>> listFactory = ArrayList::new;
List<String> newList = listFactory.get();
Stream API
Creating Streams
// From collection
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();
// From array
String[] array = {"a", "b", "c"};
Stream<String> arrayStream = Arrays.stream(array);
// From values
Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5);
Intermediate Operations
// filter - keep elements matching predicate
list.stream()
.filter(s -> s.length() > 3)
.forEach(System.out::println);
// map - transform elements
list.stream()
.map(String::toUpperCase)
.forEach(System.out::println);
// sorted - sort elements
list.stream()
.sorted()
.forEach(System.out::println);
// limit - take first n elements
list.stream()
.limit(5)
.forEach(System.out::println);
// skip - skip first n elements
list.stream()
.skip(2)
.forEach(System.out::println);
Terminal Operations
// forEach - process each element
list.stream().forEach(System.out::println);
// count - count elements
long count = list.stream().filter(s -> s.length() > 3).count();
// collect - gather results
List<String> result = list.stream()
.filter(s -> s.startsWith("A"))
.collect(Collectors.toList());
Chaining Operations
List<String> result = names.stream()
.filter(name -> name.length() > 3)
.map(String::toUpperCase)
.sorted()
.limit(10)
.collect(Collectors.toList());
Pattern Matching
instanceof with Pattern
// Traditional
if (obj instanceof String) {
String s = (String) obj;
System.out.println(s.length());
}
// With pattern matching (Java 16+)
if (obj instanceof String s) {
System.out.println(s.length());
}
// In boolean expressions
if (obj instanceof String s && s.length() > 5) {
System.out.println(s);
}
Pattern Matching in switch
String describe(Object obj) {
return switch (obj) {
case Integer i -> "Integer: " + i;
case String s -> "String of length " + s.length();
case Double d -> "Double: " + d;
case null -> "null value";
default -> "Unknown type";
};
}
Text Blocks
Multi-line Strings
String html = """
<html>
<body>
<h1>Hello, World!</h1>
</body>
</html>
""";
String json = """
{
"name": "John",
"age": 30,
"city": "New York"
}
""";
String sql = """
SELECT id, name, email
FROM users
WHERE active = true
ORDER BY name
""";
Indentation Handling
// Leading whitespace relative to closing """ is preserved
String code = """
public class Hello {
public static void main(String[] args) {
System.out.println("Hello");
}
}
""";
// Minimal indentation is stripped
Local Variable Type Inference
var Keyword
// Inferred as int
var number = 42;
// Inferred as String
var message = "Hello";
// Inferred as ArrayList<String>
var list = new ArrayList<String>();
// Inferred as HashMap<String, Integer>
var map = new HashMap<String, Integer>();
// In enhanced for loop
for (var item : list) {
System.out.println(item);
}
// In traditional for loop
for (var i = 0; i < 10; i++) {
System.out.println(i);
}
Where var Cannot Be Used
// NOT allowed:
var x; // No initializer
var arr = {1, 2, 3}; // Array initializer
var lambda = x -> x + 1; // Lambda without target type
class Foo {
var field = 10; // Fields
}
void method(var param) {} // Parameters
Records (Java 14+)
Basic Record
// Declares immutable data carrier
record Point(int x, int y) {}
// Usage
Point p = new Point(10, 20);
int x = p.x(); // Accessor method
int y = p.y();
System.out.println(p); // Point[x=10, y=20]
Record with Additional Methods
record Rectangle(int width, int height) {
// Compact constructor for validation
public Rectangle {
if (width < 0 || height < 0) {
throw new IllegalArgumentException("Negative dimensions");
}
}
// Additional method
public int area() {
return width * height;
}
// Static factory
public static Rectangle square(int size) {
return new Rectangle(size, size);
}
}
Sealed Classes (Java 17+)
Declaring Sealed Classes
public sealed class Shape permits Circle, Rectangle, Triangle {
public abstract double area();
}
// Must be final, sealed, or non-sealed
public final class Circle extends Shape {
private final double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
}
// non-sealed allows further extension
public non-sealed class Rectangle extends Shape {
private final double width, height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public double area() {
return width * height;
}
}
Sealed Interfaces
public sealed interface Vehicle permits Car, Truck, Motorcycle {
void start();
}
public final class Car implements Vehicle {
public void start() {
System.out.println("Car starting");
}
}