Looking at Java 21: Simpler Main Methods and Unnamed Classes
Java’s known (and often criticized) for its vast amount of required boilerplate and ceremony for perceived mundane tasks, at least compared to other languages. Despite the “war on boilerplate” not being the primary goal of most new features, it’s often a side effect of new additions to the language, like Records. The preview JEP 445, however, is explicitly targeted to make the first introduction to Java a breeze: simpler main methods and unnamed classes.
Table of Contents
Simpler Main Methods
Even though Java is an excellent language for complex, large, enterprise-grade multi-developer applications, it’s still intended to be a first programming language, too. That’s why the initial hurdles should be as low as possible.
Let’s take a look at how to write your first Java program.
How to Start a (Java) Program
We all know how a typical Java program starts:
It’s the “normal” entry point all of us have written many times, and in complex applications, we do it once and don’t think much about it anymore. But imagine yourself being a beginner again and wanting to learn Java. You don’t know much about Java yet and are confronted with a lot of things right now…
package declaration, which might be there, maybe not.
class declaration uses a mandatory visibility modifier (
public) that doesn’t make sense for our first program.
And if you name the file containing it not the same as the
class, it won’t compile.
Next, there’s a method aptly named
main, so it’s the actual entry point.
However, it uses a visibility modifier (
public), too, but adds in a lifetime/access modifier (
static) for good measure.
To make it even more complicated, let’s introduce var-args (
String...) or an array (
String) right in your first program.
I’ll use var-args throughout the article, but it’s interchangeable with an array.
Most of these features you need to learn at some point, but they’re primarily targeted at more complex applications.
Without knowing the details of these features, you might think that
static methods are the way to go and form a bad habit from the start.
Compare all that to the requirements for your first Python program:
That’s even the code for your first Ruby program!
So I think that perfectly illustrates what people mean when they talk about ceremony and boilerplate. For a seasoned developer and in the context of a complex program, it might make little difference, and each of the features is necessary and make sense. For newcomers, though, it’s an unnecessary hurdle compared to many other languages.
Less is More
Let’s review the Java example again and remove all the “unnecessary” things.
package declaration isn’t necessary even before Java 21, so it’s omitted.
But how about removing visibility/lifetime modifiers and the method arguments?
Still not as sleek like in other languages, but already a great improvement! And that’s exactly what the flexible launch protocol of JEP 445 will introduce:
- No visibility modifier is needed for the
mainmethod lookup mechanic, searching for the first available entry point of:
- Any non-
static void main(String... args)method
- Any non-
static void main()method
- Any non-
By allowing us to remove much of the ceremony for single-class programs, the code isn’t as intimidating as before, and we even have a choice of options!
The best thing, though, is that it’s implemented in a Java-compatible way. There’s no special syntax needed, it’s all valid code.
Removing modifiers and method arguments isn’t all that JEP 445 contains, though.
The way Java projects are structured is simple: every class is in a package and every package is in a module.
This method of namespacing and compartmentalizing your code is prevalent in many programming languages and a necessity for any program consisting of more than a few classes.
However, just like
public static void main(String... args) method in the previous section, it’s another hurdle for simple, one-class programs.
That’s why JEP 445 also introduces unnamed classes, simplifying our code even further.
The change that makes this possible is how the compiler treats a source with methods and fields not enclosed in a class. Any unenclosed fields and methods, and nested classes, declared in the file build an unnamed top-level class.
As the class has no name, we can’t reference or instantiate it any way ourselves.
It resides in the unnamed package in the unnamed module.
Besides that, it behaves almost like a “normal” class declaration.
We can’t use certain features, though, like implementing an interface, extending another type, referencing the class by name, generating documentation with
Even though the code is no longer valid Java syntax on the surface, it still is behind the scenes.
If the code doesn’t have a
static main method, running an unnamed class is equivalent to:
Why This Matters
As a seasoned developer with years of Java under your belt you might not see why this is important, especially since you had to endure it and still become an awesome Java dev. Still, Java throws a lot at newcomers that can be avoided, as this JEP shows.
Newcomers should only need to concentrate on the relevant code for their first contact, so omitting concepts and constructs they don’t immediately need makes a lot of sense. It’s not that they don’t need to learn them at some point, but now they can choose to do so at their own pace.
Ok, so why not make it even simpler by removing the
main method altogether?
Well, because the Java language designers put quite a bit of thought into any new addition, especially if it affects the language itself.
As I talked about in the previous article, Java’s language design strives towards improvement without compromise.
main method and treating the whole code as an executable logic unit would affect other Java semantics, such as how local variables behave differently from fields, for example.
That might not be a big deal in many cases but would hinder growing your unnamed class into a bigger program, as you progress in your learning journey.
Should I use a Preview Feature?
As both features, simpler main methods and unnamed classes, are only relevant to single-class programs, I don’t see any harm in using them.
You can use the preview feature in two ways:
Compiling and running your code
Using the Source Code Launcher (JEP 330)
Looking at Java 21
- String Templates (JEP 430)
- Simpler Main Methods and Unnamed Classes (JEP 445)
- Sequenced Collections (JEP 431)
- Scoped Values (JEP 446)
- Switch Pattern Matching (JEP 441)
- Feature Deprecations (JEP 449, 451)
- Record Pattern Matching (JEP 440)
- Generational ZGC (JEP 439)
- Virtual Threads (JEP 444)
- The Little Things