IntelliJ IDEA Java

Java 24: ‘HelloWorld’ and ‘main()’ meet minimalistic

(Originally published for Java 22, this post has been updated to include changes from Java 23 and 24.)

“Just ignore the terms class, public, static and args[] for now; we’ll talk about it later”. If you have ever mentioned these lines to a new Java student, who is about to execute their first ‘HelloWorld’ program, know that this is changing. If you are that student, well, congratulations, getting started is simpler in Java :-).

Initially released as a preview language feature in Java 21, Simple Source Files and Instance Main Methods is currently being previewed for the fourth time in Java 24. This feature is for folks starting to learn Java. It simplifies the initial steps for students when they start learning basics, such as variable assignment, sequence, conditions and iteration. Students no longer need to declare an explicit class to develop their code, or write their main() method using this signature – public static void main(String []), or use System.out.println() to output values to console. With this feature, classes could be declared implicitly, the main() method can be created with a shorter list of keywords and println()/ readln() methods can be used to write to and read from console.

In this blog post, I’ll cover why and how this feature is helpful for students using hands-on coding examples. I’ll also cover some details and frequently asked questions relevant to educators or experienced programmers. Let’s get started.

Hi Students – Your HelloWorld code is changing

HelloWorld refers to the first piece of executable code that anyone writes when they start learning a new language or a framework. It usually includes executing bare minimum code, such as printing ‘Hello World’ on the console to ensure the setup is okay. In Java, it meant writing a class with a method main(). As the name suggests, main() is one of the most important methods. It defines the entry point of execution, when a class executes.

What happens when you see that your ‘HelloWorld’ code executed as expected? It brings a lot of joy and a sense of winning to the one executing it. I still remember the time when I was able to run my first piece of code in Java. I believe we kind of never forget our firsts, both in life, love and coding!

Let’s see how your HelloWorld code is changing.

Class ‘HelloWorld’ before and after Java 21

Before Java 21, you would need to define a class, say, HelloWorld, that defined a main() method with a specific list of keywords, to print any text, say, ‘Hello World’ to the console, as follows:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}

With Java 21 this initial step was shortened and changed a little with Java versions 22, 23 and 24. Now (with Java 24), you can define a source code file, say, HelloWorld.java, with the following code, to print a message to the console (it doesn’t need to define a class, it has a shorter signature for method main() and System.out.println() is shortened to println()):

void main() {
    println("Hello World");
}

The preceding code is simpler than what was required earlier. Let’s see how this change could help you focus on what you need, rather than what you don’t.

Reducing cognitive complexity

One of the main benefits of the minimalistic main() method and not having to write an explicit class is – the code is concise and to the point. It introduces less concepts or keywords that could otherwise overwhelm new students. Here’s an image to compare the difference in the preceding code snippets:

Of course, you could ignore the terms class, public, static, args[], System.out as suggested by your teacher, but they do use space in your memory every time you look at it. These little things pile up, in coding or life, overwhelming one. The minimalist main() and implicit enclosing class reduce cognitive complexity for you.

Compiling and executing your code

Once you are done writing your code, the next step is to execute it.

On the command prompt, you could use just the java command to compile and execute this code (courtesy of Launch Single-File Source-Code Programs, since Java 11). Assuming you have defined your code in a source code file, say, HelloWorld.java, you could use the following commands to execute it:

C:\code\MyHelloWorldProject\java HelloWorld.java

For your quick information, since Java 22, it is possible to skip the compilation process multiple for code defined in multiple source code files too. Check out this link for details.

However, since ‘Simple Source Files and Instance Main Methods’ is a preview language feature, you should add the flag --enable-preview with --source 24 with these commands, as follows:

C:\code\MyHelloWorldProject\java --enable-preview --source 24 HelloWorld.java

Sooner or later, you might switch to using an IDE to write your code. If you wish to use IntelliJ IDEA for creating instance main methods, here’s a quick list of steps to follow. Create a new Java project, select the build system as IntelliJ (so you could use Java compiler and runtime tools), create a new file, say, HelloWorld.java with your instance main method and set the properties to use Java 24, before you run your code, as shown in the following gif (It could save you from typing out the compilation/ execution commands on the command prompt each time you want to execute your code):

Are you wondering if it would be better to create a ‘Java class’ instead of a ‘File’ in the ‘src’ folder? The option of selecting a Java class would generate the body of a bare minimum class, say, public class HelloWorld { }. Since we are trying to avoid unnecessary keywords in the beginning, I recommended creating a new ‘File’ which wouldn’t include any code.

If you plan to use IntelliJ IDEA, here are its configuration details. Java 24 support is available in IntelliJ IDEA 2025.1 EAP. The final release of this version is planned for March 2025.

In your Project Settings, set the SDK to Java 24. For the language level, select ‘24 (Preview) – Flexible consructor bodies, simple source files, etc.’ on both the Project and Modules tab, as shown in the below settings screenshot:

Let’s move beyond the simple ‘Hello World’ code and explore further.

What else can main() do apart from printing messages to the console?

It is an interesting question. Let’s check out a few code examples below to learn more about it.

Example 1. Variable declarations, assignments and simple calculations

The initial steps in learning programming start with basics, such as declaring variables, assigning values, simple calculations and checking the values (by printing them to the console). Here’s a common example that covers them all – calculating the total amount returned by a bank for a specified interest rate and principal amount. Let’s define this code in a source code file, say, CalcInterest.java:

void main() {
    double principal = 17000;
    double rate = 0.07;
    double interest;

    interest = principal * rate;
    principal = principal + interest;

    println("Interest            = " + interest);
    println("Amount after 1 year = " + principal);
}

In the next example, let’s code something interesting – more than basic calculations, such as, printing a pattern .

Example 2. Print patterns, such as, big letters using a specified character

Here’s another interesting problem that includes basics, such as, variable assignments, conditional statements (via if-else) and iteration (via for).

The following code prints a letter P, using the letter X (as specified by the variable charToPrint), that is 10 lines in height (as specified by the variable size):

void main() {
    int size = 10;
    char charToPrint = 'X';
    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size; j++) {
            if (j == 0 || (i == 0 || i == size / 2) && j < size - 1 || (j == size - 1 && i <= size / 2)) {
                print(charToPrint + " ");
            } else {
                print("  ");
            }
        }
        println();
    }
}

The following gif shows the output of the preceding code:

Do you think you would be up for creating methods that could include logic to print other letters of the alphabet (A – Z), or even other alphabets (like the Devnagri)? Just asking :-)

Before we move forward, did you know you could overload methods, that is, define multiple methods with the same name, such as, ‘main’ in your source code file? Which of these methods main() method would execute when you run your source code file? IntelliJ IDEA displays the run icon next to the main() method in your source code. The following gif shows how that icon moves when you change the signature of a main method:

Let’s take a step forward in the next example by animating words spanning multiple lines.

Example 3. Animating multiline text – one word at a time

Soon, you’ll find yourself using other concepts like, say, iterating words in a String, single and multiple line comments, using other classes from core Java API like Threads, perhaps also some exception handling. Here’s an example of a multiline String that is displayed like animated text, one word at a time (all of which can be coded within the main() method):

/**
 * The main method animates the display of lines of text by printing each word with a pause in between.
 * It splits the given text into individual lines, then splits each line into words.
 * It prints each word followed by a space, and pauses for a specified amount of time between each word.
 */
void main() {
    // Text to animate
    String text = """
                  Why did the Java programmer bring a shovel to work? To 'dig' into the data structures!
                  Why was the Java developer always so calm? Because they never lost their stack trace!
                  Why did the Java developer go broke? Because he used up all his cache!
                  Why did the Java developer always carry a pen? To 'interface' with their notes!
                  """;

    // Split into individual lines
    String[] lines = text.split("\n");

    // Loop through lines
    for (String line : lines) {
        String[] words = line.split(" ");

        // Loop through words
        for (int i = 0; i < words.length; i++) {

	        // Print the word
            print(words[i] + " ");
            // Pause to create the animation effect
            try {
                Thread.sleep(200); // Change this number to modify word display speed
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // Start printing on the next line
        println();
    }
}

The following gif shows the output of the preceding code:

If you are feeling adventurous, perhaps you could try other animations too – like animating each letter or decreasing the speed by which the words are printed to console. Are you up for this challenge :-)

Example 4. Data structure problems

I’ve seen that both students and experienced programmers enjoying solving problems that involve data structures. So, here’s one for you (which can be coded using just the main() method): Given an array of integers, find the maximum subarray sum. The subarray must be contiguous, but could be of any length.

Below is the code for your reference:

void main(String[] args) {
    int[] nums = {-2, 1, -3, 4, -1, 2, 1, -5, 4};
    int maxEndingHere = nums[0];
    int maxSoFar = nums[0];

    for (int i = 1; i < nums.length; i++) {
        maxEndingHere = Math.max(nums[i], maxEndingHere + nums[i]);
        maxSoFar = Math.max(maxSoFar, maxEndingHere);
    }

    int maxSum = maxSoFar;
    println("Maximum subarray sum: " + maxSum);
}

Example 5. Text based Hangman game

Here’s another example that shows code for a text based hangman game – a simple game that asks you to guess one letter at a time. If the letter appears in the target guess word, it reveals itself in the word. This example uses the Scanner class from the Java API, which could be accessed either by using the full name while defining its variable, or by including an import statement outside the main() method (this helps you to get familiar with using concepts like importing other classes in an incremental way):

void main() {
    String[] words = {"java", "programming", "computer", "algorithm", "developer"};
    String targetWord = words[(int) (Math.random() * words.length)];

    StringBuilder guessedLetters = new StringBuilder(targetWord.length());
    for (int i = 0; i < targetWord.length(); i++) {
        guessedLetters.append("_");
    }

    int attempts = 6;
    println("Welcome to Hangman!");
    println("Try to guess the word. You have " + attempts + " attempts.");

    while (attempts > 0) {
        println("Current word: " + guessedLetters);
        String input = readln("Enter a letter: ");
        char guess = input.charAt(0);

        boolean found = false;
        StringBuilder updatedWord = new StringBuilder(guessedLetters);
        for (int i = 0; i < targetWord.length(); i++) {
            if (targetWord.charAt(i) == guess) {
                updatedWord.setCharAt(i, guess);
                found = true;
            }
        }

        if (found) {
            guessedLetters = updatedWord;
            println("Correct guess! Updated word: " + guessedLetters);
        } else {
            attempts--;
            println("Incorrect guess! You have " + attempts + " attempts left.");
        }

        if (guessedLetters.toString().equals(targetWord)) {
            println("Congratulations! You guessed the word: " + targetWord);
            break;
        }
    }

    if (attempts == 0) {
        println("Game Over. The word was: " + targetWord);
    }   
}

The following gif shows the output of the preceding code:

Here’s another challenge for you – I just realized that the input in the preceding code is case sensitive. It doesn’t work if you type ‘A’ instead of ‘a’. Could you make it ignore the case of the letters that are typed?

The intent with all these examples is that you could use minimum ceremonial code to start learning basics in Java.

Changing an implicit class to a regular class

When you are ready to level up and work with other concepts like user defined classes, you could also covert the implicit classes and code that we used in the previous examples, to regular classes, as shown below:

In the next section, I’ll answer a few questions that might seem more interesting for folks who are not new to Java and are interested in knowing more about this feature.

Some details and FAQs

Let’s start by sharing that the name of this feature changed from its initial release, which is not common.

A little bit of history

The name of this feature changed more than once since it was previewed in Java 21. This feature was introduced as Unnamed Classes and Instance Main Methods. Its name changed to Implicitly Declared Classes and Instance Main Methods in Java 22. There was no change to its name in Java 23. In Java 24, the name of this feature is changed again – Simple Source Files and Instance Main Methods.

Changing name of a Java feature is not usual. It could happen if the changes in the feature no longer reflect the intention of its initial name.

What do you mean by ‘instance’ main() method?

This feature refers to the main method as an instance main method since it doesn’t use the keywords static with its declaration. In the past, the main method was defined using the static keyword, so that it could be accessed even without the need of creating any objects of the class in which it was defined.

Behind the scenes, a source code file with an instance main method is compiled to a regular class with a no-arg constructor. Its instance main method is executed by creating an instance of this class, followed by calling main() on it.

What happens when you create a source code file with method main(), but no class declaration?

Behind the scenes, the Java compiler creates an implicit top level class, with a no-argument constructor, so that these classes don’t need to be treated in a way that is different to the regular classes.

Here’s a gif that shows a decompiled class for you for the source code file AnimateText.java:

Interacting with console – println() vs. System.out.println() calls

To make it simpler for new developers to interact with the console, that is, output messages to console and to read input from it, a new class – java.io.IO was created in Java 23. It contains just a handful of overloaded readln() and println() methods (as shown below):

Class java.io.IO is automatically imported in implicit classes. So, instead of using System.out.println(), you can now use println() to output messages to a console (and readln() to read from console). Interestingly, println() was added to this class in Java 24.

Whenever you are curious to find in which class or an interface a method is defined in, you can access this information by either using Quick Documentation (displays method and class details without switching to the source), or by using the Navigate feature in IntelliJ IDEA; navigating to method’s definition (as shown in the following gif):

Thanks to another newer feature, that is, Module Import Declarations, implicit classes automactically import all public classes exported by the module java.base.

Does this feature introduce a separate beginner’s toolchain?

I’m an educator and I fear that if we introduce simpler processes to students that are not mainstream, that could impact how they transition to learning other Java concepts later. I’m glad to share that this feature doesn’t do that.

With implicit classes and instance main methods, students can still compile and run their code using the same tools and process, as are required when the size of their sample code or count for their source code files increase.

Variations of the main method in the implicit class

As we are aware, a method can be overloaded. Does that imply an implicit class can define multiple main methods? If yes, which one of them qualifies as the ‘main’ method? This is an interesting question. First of all, know that you can’t define a static and non-static main method with the same signature, that is, with the same method parameters. The following method are considered valid main() methods in an implicit class:

public static void main(String args[]) {}
public void main(String args[]) {}
public static void main() {}
static void main() {}
public void main() {}
void main() {}

If there is no valid main method detected in an implicit class, IntelliJ IDEA could add one for you, as shown in the following gif:

Educators could use this feature to introduce other concepts to the students in an incremental way

If you are an educator, you could introduce your students to other commonly used programming practices, such as creating methods- that is delegating part of your code to another method and calling it from the main method. You could also talk about passing values vs. variables to these methods.

The following gif shows how to do it:

There are other practices too that I would have loved to mention like implementing the abstract methods of an interface, but, I think it would be better to leave them for another blog post.

Preview Features

Simple Source Files and Instance Main Methods is in its fourth preview in Java 24. With Java’s new release cadence of six months, new language features are released as preview features. They may be reintroduced in later Java versions in the second or more preview, with or without changes. Once they are stable enough, they may be added to Java as a standard language feature.

Preview language features are complete but not permanent, which essentially means that these features are ready to be used by developers, although their finer details could change in future Java releases depending on developer feedback. Unlike an API, language features can’t be deprecated in the future. So, if you have feedback about any of the preview language features, feel free to share it on the JDK mailing list (free registration required).

Because of how these features work, IntelliJ IDEA is committed to only supporting preview features for the current JDK. Preview language features can change across Java versions, until they are dropped or added as a standard language feature. Code that uses a preview language feature from an older release of the Java SE Platform might not compile or run on a newer release.

Summary

Java language designers are reducing the ceremony that is required to write the first HelloWorld code for Java students, by introducing implicitly declared classes, instance main methods and shortened calls to println()/ readln() to output messages and read data from the console. New students can start with bare minimum main() method, such as, void main() and build strong programming foundation by polishing their skills with basics like sequence, selection and iteration.

Some folks might argue that this is a simple change, or that other languages already have it. For the first point, I’d say, it is better to be late than never. Also, in life and coding, it is always better to focus on what you want to do, rather than focusing on what you don’t want to. For the latter point, I’d say, good for those languages :-)

Stay tuned for my next blog post, in which I’ll cover more examples on creating scripts and utilities using implicit classes – for both new and experienced developers.

image description

Discover more