Java Features
Explore important modern Java features introduced from Java 8 through recent Java releases.
1. Introduction to Java
Modern Java has evolved significantly beyond traditional object-oriented programming. New language features and APIs have improved readability, safety, performance, and developer productivity.
Some of the most important modern Java features include:
- Lambda Expressions
- Functional Interfaces
- Stream API
- Optional
- Local variable type inference using
var - Switch expressions
- Pattern matching
- Text blocks
- Records
- Sealed classes
- Private interface methods
- Modern Date and Time API
2. Java 8 Features
Java 8 was one of the most important releases in Java history. It introduced functional programming capabilities and major API improvements.
| Feature | Purpose |
|---|---|
| Lambda Expressions | Write concise function-like behavior. |
| Functional Interfaces | Represent a single abstract operation. |
| Stream API | Process collections declaratively. |
| Optional | Represent potentially absent values. |
| Default Methods | Add behavior to interfaces. |
| java.time | Modern date and time handling. |
3. Lambda Expressions
Lambda expressions provide a concise way to represent behavior.
List<String> names =
List.of("Amit", "Neha", "Rahul");
names.forEach(
name -> System.out.println(name)
);
Lambda expressions are commonly used with functional interfaces, collections, and streams.
4. Functional Interfaces
A functional interface has exactly one abstract method.
Examples include Predicate, Function,
Consumer, and Supplier.
Predicate<Integer> positive =
number -> number > 0;
System.out.println(
positive.test(10)
);
5. Stream API
The Stream API allows collections to be processed using a declarative pipeline of operations.
List<Integer> numbers =
List.of(1, 2, 3, 4, 5, 6);
List<Integer> evenNumbers =
numbers.stream()
.filter(n -> n % 2 == 0)
.toList();
System.out.println(evenNumbers);
Common stream operations include:
filter()map()sorted()distinct()limit()reduce()collect()toList()
6. Optional
Optional represents a value that may or may not be present.
It can help make absence explicit and reduce some common null-handling
problems.
Optional<String> name =
Optional.ofNullable(null);
String result =
name.orElse("Unknown");
System.out.println(result);
7. var - Local Variable Type Inference
Java 10 introduced var for local variable type inference.
The compiler determines the variable's static type from its initializer.
var name = "Samadhan";
var age = 22;
var salary = 85000.50;
System.out.println(name);
System.out.println(age);
System.out.println(salary);
The variable still has a fixed compile-time type. Java is not becoming dynamically typed.
8. Switch Expressions
Modern switch expressions can directly produce a value.
int day = 2;
String result = switch (day) {
case 1 -> "Monday";
case 2 -> "Tuesday";
case 3 -> "Wednesday";
default -> "Other";
};
System.out.println(result);
Switch expressions make many branching operations more concise.
9. Pattern Matching
Pattern matching simplifies type checks and conditional logic.
Object value = "Java";
if (value instanceof String text
&& text.length() > 3) {
System.out.println(
text.toUpperCase()
);
}
The variable text is available after the pattern has
successfully matched and the condition permits its use.
10. Text Blocks
Text blocks provide a convenient syntax for multiline string literals.
String json = """
{
"name": "Java",
"version": 21
}
""";
System.out.println(json);
Text blocks are useful for JSON, HTML, SQL, XML, and other multiline text.
11. Records
Records provide a concise way to model data-centric classes.
record Employee(
int id,
String name,
double salary
) {
}
Employee employee =
new Employee(101, "Sejl", 50000);
System.out.println(
employee.name()
);
Records automatically provide important members such as accessors,
equals(), hashCode(), and
toString().
12. Sealed Classes
Sealed classes and interfaces allow developers to explicitly restrict which types can directly extend or implement a type.
sealed interface Payment
permits CardPayment, CashPayment {
}
final class CardPayment
implements Payment {
}
final class CashPayment
implements Payment {
}
This makes the inheritance hierarchy explicit and controlled.
13. Private Interface Methods
Java 9 introduced private methods in interfaces. They allow common implementation logic to be shared by default and static methods.
interface Logger {
default void info(String message) {
System.out.println(
format(message)
);
}
private String format(String message) {
return "[INFO] " + message;
}
}
14. Modern Date and Time API
Java 8 introduced the java.time API, which provides
immutable and thread-safe date and time types.
LocalDate today =
LocalDate.now();
LocalDate nextWeek =
today.plusWeeks(1);
System.out.println(today);
System.out.println(nextWeek);
Common classes include:
LocalDateLocalTimeLocalDateTimeZonedDateTimeInstantDurationPeriod
15. Convenient Collection Factory Methods
Modern Java provides convenient factory methods for creating unmodifiable collections.
List<String> names =
List.of("Amit", "Neha", "Rahul");
Set<Integer> numbers =
Set.of(10, 20, 30);
Map<Integer, String> employees =
Map.of(
101, "Amit",
102, "Neha"
);
16. Modern HTTP Client
Java 11 introduced the standard HttpClient API for
making HTTP requests.
HttpClient client =
HttpClient.newHttpClient();
HttpRequest request =
HttpRequest.newBuilder()
.uri(
URI.create(
"https://example.com"
)
)
.GET()
.build();
HttpResponse<String> response =
client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
System.out.println(
response.statusCode()
);
17. Modern File API
The NIO.2 API provides modern file and path handling through
classes such as Path and Files.
Path path =
Path.of("data.txt");
Files.writeString(
path,
"Hello Java"
);
String content =
Files.readString(path);
System.out.println(content);
18. Modern Stream Collection
Recent Java versions provide convenient terminal operations such as
toList().
List<String> result =
names.stream()
.filter(
name -> name.length() > 4
)
.toList();
System.out.println(result);
19. Modern String Methods
Modern Java versions have added useful methods to the
String API.
String text = "Java\nPython\nC#";
text.lines()
.forEach(
line -> System.out.println(line)
);
Other useful APIs include methods such as isBlank(),
strip(), stripLeading(),
stripTrailing(), and repeat().
20. Pattern Matching with Switch
Modern Java versions have expanded switch to support pattern-based logic.
static String describe(Object value) {
return switch (value) {
case Integer number
-> "Integer: " + number;
case String text
-> "String: " + text;
case null
-> "Null value";
default
-> "Other type";
};
}
Pattern matching can make complex type-based branching easier to read.
21. Combining Modern Features
Modern Java features can be combined to create concise and strongly typed domain models.
sealed interface Result
permits Success, Failure {
}
record Success(String message)
implements Result {
}
record Failure(String error)
implements Result {
}
static String process(Result result) {
return switch (result) {
case Success success
-> "Success: "
+ success.message();
case Failure failure
-> "Failure: "
+ failure.error();
};
}
22. Important Java Feature Timeline
| Java Version | Important Features |
|---|---|
| Java 8 | Lambda, Stream API, Optional, default methods, java.time |
| Java 9 | Private interface methods, module system |
| Java 10 | Local variable type inference with var |
| Java 11 | Standard HttpClient and additional APIs |
| Java 14 | Switch expressions standardized |
| Java 15 | Text blocks standardized |
| Java 16 | Records and pattern matching for instanceof standardized |
| Java 17 | Sealed classes standardized |
| Java 21 | Pattern matching for switch and record patterns standardized |
23. Benefits of Modern Java
- Cleaner and more readable code.
- Reduced boilerplate.
- Better support for functional programming.
- Improved collection processing.
- Safer and clearer null handling.
- Better domain modeling.
- More expressive control flow.
- Improved API design.
- Modern date and time handling.
- Better support for concurrent and asynchronous programming.
24. Best Practices
- Use modern features when they improve readability.
- Do not use
varwhen the inferred type is unclear. - Use streams when collection processing becomes clearer.
- Avoid unnecessarily complex stream pipelines.
- Use records for data-centric immutable models.
- Use sealed types when a hierarchy should be intentionally restricted.
- Prefer
java.timeover legacy date/time classes. - Use Optional thoughtfully rather than everywhere.
- Keep modern code understandable for the team maintaining it.
25. Interview Questions
Final Module Summary
You have now completed the major Modern Java topics:
- var and local variable type inference
- Switch expressions
- Pattern matching
- Text blocks
- Records
- Sealed classes
- Modern interfaces
- Modern Java APIs and language features
These features help Java developers write cleaner, safer, more expressive, and maintainable applications.