Advanced Concepts
Here are some of the most impactful enhancements introduced in Java 17 and Java 21, designed to improve code clarity, performance, and overall developer productivity:
- Simplified Main Method
- Text Block
- Switch Case enhancement (return + yield)
- NullPointerException Error Message
- Sealed Class
- Record
- RMI Activation

1. Simplified main method:
The main method acts as the entry point for program execution and is traditionally defined as public static void main(String[] args). However, in Java 21, it got simplified to reduce boilerplate code and improve readability.
Before Java 21:
public class Practice {
public static void main(String[] args) {
System.out.println("Hello World!!!");
}
}
Starting from Java 21:
public class Practice {
void main() {
System.out.println("Hello World!!!");
}
}
OUTPUT:
Hello World!!!
Imponent Note: Simplified main method doesn’t allow us to pass parameter / parameters.
2. Text Block
Text Blocks got introduced in Java 13 and 14 and got stable in Java 15, it allow us to write multi-line string literals. It reduces the need for escape characters while writing JSON, XML, etc.
Before Java 21:
public class Practice {
public static void main(String[] args) {
String data = "{\n" +
" \"username\": \"testuser\",\n" +
" \"password\": \"securepassword\"\n" +
"}";
System.out.println("Hello World!!!");
}
}
Starting from Java 21:
public class Practice {
public static void main(String[] args) {
String data = """
{
"username": "testuser",
"password": "securepassword"
}
""";
System.out.println("Hello World!!!");
}
}
OUTPUT:
{
"username": "testuser",
"password": "securepassword"
}
3. Switch Case return + yield enhancement
Switch case enhancement got finalized in Java 14. Enhanced feature allow us to return value directly from switch blocks using return or yield.
public class Practice {
public static void main(String[] args) {
System.out.println(getWorkByDay("wednesday"));
}
/**
* Returns the work assigned based on the given day using a switch expression.
*
* @param day the day of the week (case-insensitive)
* @return the assigned task for the day, or "Invalid day" if no match is found
*/
public static String getWorkByDay(String day) {
return switch (day.toLowerCase()) {
case "monday" -> "Planning"; // Maps Monday to Planning task
case "tuesday", "wednesday" -> {
System.out.println("Inside Tuesday and Wednesday Switch Case");
yield "Development"; // Yields and return Development for both Tuesday and Wednesday
}
default -> "Invalid day"; // Handles all other unmatched inputs
};
}
}
Important Note: return exits the method, whereas yield returns a value from a switch expression block.
4. Enhanced NullPointerException Error Message
NullPointerException diagnostics got introduced in Java 14, including the specific variable that is null, along with the method name, source file name and line number where the exception occurred.
Below is the example of NullPointerException before and after Java 21:
Before Java 21:
java.lang.NullPointerException
at Practice.main(Practice.java:31)
Starting from Java 21:
java.lang.NullPointerException: Cannot invoke "String.length()" because "str" is null
at Practice.main(Practice.java:31)
5. Sealed Classes
Sealed classes is a powerful feature got introduced as preview part of Java SE 15 and finally in Java 17.
Its a new way to control inheritance.
Sealed classes are designed to restrict which classes or interfaces can extend or implement them. This feature allows developers to have more control over the class hierarchy, ensuring that only specific classes can be subtypes. By doing so, sealed classes enhance the maintainability, security, and comprehensibility of the code.
A sealed class or interface specifies a limited set of permitted subclasses or implementations. These permitted subclasses must be explicitly declared within the sealed class or interface.
The subclasses can be one of the following:
Final: The subclass cannot be extended further.
Sealed: The subclass can be extended but only by a specified set of classes.
Non-Sealed / Non-Final: The subclass can be extended without restrictions.
Here’s the basic syntax:
public sealed class BaseClass permits SubClass1, SubClass2 {
// Class content
}
public final class SubClass1 extends BaseClass {
// Class content
}public sealed class SubClass2 extends BaseClass permits SubSubClass {
// Class content
}public final class SubSubClass extends SubClass2 {
// Class content
}
In above example, BaseClass is a sealed class that permits SubClass1 and SubClass2 to extend it. SubClass1 is a final class, while SubClass2 is a sealed class that permits SubSubClass to extend it.
Follow link to read more about Sealed Class.
6. Record
Record is a special kind of class which allow us to create immutable data classes by minimizing the need for repetitive boilerplate code.
Below is the record overall syntax:
public record Student(int studentID, Stirng name) {}
Above Record is equivalent to below class:
public final class Student {
private final int studentID;
private final String name;
public Student(int studentID, String name) {
this.studentID = studentID;
this.name = name;
} public int studentID() {
return studentID;
} public String name() {
return name;
} @Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Student)) return false;
Student student = (Student) o;
return studentID == student.studentID &&
name.equals(student.name);
} @Override
public int hashCode() {
return java.util.Objects.hash(studentID, name);
} @Override
public String toString() {
return "Student[studentID=" + studentID + ", name=" + name + "]";
}
}
Record allow us to create a class having:
- Constructor: A record automatically generates a constructor with parameters matching its declared fields at the time of record creation. A default (no-argument) constructor is not created. If needed, you can define one explicitly.
- Getters: It will follow the same naming convention as the fields they represent. For example, studentID() and name())
- Inbuilt: it will have toString(), equals(), and hashCode() methods.
Follow link to read more about Record in Java

Imran Khan, Adobe Community Advisor, certified AEM developer and Java Geek, is an experienced AEM developer with over 12 years of expertise in designing and implementing robust web applications. He leverages Adobe Experience Manager, Analytics, and Target to create dynamic digital experiences. Imran possesses extensive expertise in J2EE, Sightly, Struts 2.0, Spring, Hibernate, JPA, React, HTML, jQuery, and JavaScript.