Breaking Down Java’s “Hello World”

Introduction

The first piece of code most Java students see is the “Hello World” application. This program prints the message “Hello World” to the console and terminates. But, despite the simplicity of what the program does, the code itself has a lot going on.

Our first Java program bombards us with keywords like class, public, static, and void. There’s a String[] variable thrown in there as well, for good measure. Why is all of this code here, and what does it do?

In this blog post, we’ll break down Java’s “Hello World” program, and explain what all of the component pieces actually mean.

The “Hello World” Application

Let’s take a look at one version of the code for “Hello World” (we’ll use some other versions as well, but this one is the classic):

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

When I’m tutoring Java programming at the beginning of a semester, I’ll refer to the first two lines of code (the ones containing “class” and “main“) as “magic”. They’re simply what we have to surround our “actual” code with, to get our program to run. I’ll also simplify “System.out“, saying it’s just something that goes in front of “println()” to “make it work”.

These simplifications work well enough at the beginning of the semester. But, by the end of an introductory course in Java programming, we’d like to fully understand all the pieces of code in “Hello World” , and what each word really does. Let’s dive right in.

The class Declaration

First, let’s focus on the class keyword. This keyword denotes that HelloWorldPrinter is a class. We can instantiate objects of this class:

public class HelloWorldPrinter
{
    public static void main(String[] args)
    {
        HelloWorldPrinter hwp = new HelloWorldPrinter();
    }
}

That call to new works because there’s an implicit constructor in the HelloWorldPrinter class:

public class HelloWorldPrinter
{
    // public HelloWorldPrinter()
    // {
    // }

    public static void main(String[] args)
    {
        HelloWorldPrinter hwp = new HelloWorldPrinter();
    }
}

To get one possible implementation of “Hello World” working (different from the classic implementation we saw earlier), we could add an instance method to our class, which will be responsible for producing the output:

public class HelloWorldPrinter
{
    // public HelloWorldPrinter()
    // {
    // }

    public void outputMessage()
    {
        System.out.println("Hello World");
    }

    public static void main(String[] args)
    {
        HelloWorldPrinter hwp = new HelloWorldPrinter();
        hwp.outputMessage();
    }
}

The public Modifier

The public access modifier is used in both the class declaration and the main method declaration. In both of these cases, the access modifier means that the class and the method can be used by or called from any other code.

As an example, let’s consider the following version of HelloWorldPrinter:

public class HelloWorldPrinter
{
    public static void outputMessage()
    {
        System.out.println("Hello World");
    }

    public static void main(String[] args)
    {
        HelloWorldPrinter.outputMessage();
    }
}

Another class can make use of the HelloWorldPrinter class and its public methods, regardless of where in the codebase the other class is located:

public class SomeOtherClass
{
    public static void main(String[] args)
    {
        System.out.println("Hello Mars");
        HelloWorldPrinter.outputMessage();
        System.out.println("Goodbye Mars");
    }
}

Compiling and running the code, we see that SomeOtherClassmain method produces its own output on either side of the HelloWorldPrinter class’ output:

% javac HelloWorldPrinter.java SomeOtherClass.java
% java SomeOtherClass
Hello Mars
Hello World
Goodbye Mars

As an interesting aside, there’s no reason we couldn’t instead call HelloWorldPrinter‘s main method from SomeOtherClass. Because HelloWorldPrinter‘s main method is public, we can call it from anywhere:

public class SomeOtherClass
{
    public static void main(String[] args)
    {
        System.out.println("Hello Mars");
        HelloWorldPrinter.main(null);
        System.out.println("Goodbye Mars");
    }
}

(We just use null as the argument to main, since HelloWorldPrinter‘s main method ignores its args parameter anyway.)

The static Keyword

The next keyword we come to is the static keyword, used in the method declaration for main:

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

The static keyword means that the method doesn’t belong to any object of the HelloWorldPrinter class. Instead, it belongs to the class itself.

Let’s illustrate this difference by adding both a static method and an instance method to the HelloWorldPrinter class:

public class HelloWorldPrinter
{
    public static void outputStatic()
    {
        System.out.println("Hello Static");
    }

    public void outputInstance()
    {
        System.out.println("Hello Instance");
    }

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

Instance methods can only be called on objects, and cannot be called on the class itself:

public class HelloWorldPrinter
{
    public void outputInstance() {...}

    public static void main(String[] args)
    {
        HelloWorldPrinter.outputInstance();  // WRONG

        HelloWorldPrinter hwp = new HelloWorldPrinter();
        hwp.outputInstance();
    }
}

Static methods, on the other hand, should only be called on the class itself, and shouldn’t be called on objects:

public class HelloWorldPrinter
{
    public static void outputStatic() {...}

    public static void main(String[] args)
    {
        HelloWorldPrinter.outputStatic();

        HelloWorldPrinter hwp = new HelloWorldPrinter();
        hwp.outputStatic();  // WRONG
    }
}

With that in mind, what does it mean for us that the main method is static — that the place where our code starts belongs to the HelloWorldPrinter class, not to any object of that class? It means any instance variables or instance methods in the HelloWorldPrinter class won’t be available to the static main method directly; we have to construct an object of type HelloWorldPrinter to use them.

In fact, because the main method will always be static, it’s a common idiom to construct a new object that represents your application and its resources, then invoke a single method on that object to run the application:

public class HelloWorldPrinter
{
    private void runProgram() {...}

    public static void main(String[] args)
    {
        HelloWorldPrinter hwp = new HelloWorldPrinter();
        hwp.runProgram();
    }
}

The void Return Type

The void keyword in the main method declaration indicates that the main method doesn’t return a value. We can contrast this with a method that maybe answers a question, such as what’s the sum of two numbers:

public static int sum(int a, int b)
{
    return a + b;
}

The main method simply runs and terminates, without any returned value. If you want to terminate the main method early, the following code that uses just a return statement is correct:

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

But, the following code is not, because main is a void method:

public static void main(String[] args)
{
    System.out.println("Hello World");
    return 0;  // WRONG
}

The main Method Name

The name of the main method is significant because it tells the Java Virtual Machine (JVM) where to begin execution of your code. When you execute the JVM on a class, it looks for a main method in the class to start running.

Let’s go back to our project with two classes:

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

and:

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

We can compile the code:

% javac HelloWorldPrinter.java SomeOtherClass.java

Then, when we tell the JVM which class we want to execute, the JVM will look for the main method in that class to run:

% java HelloWorldPrinter
Hello World

or:

% java SomeOtherClass
Hello Mars

Your code in a large project could have numerous main methods in different classes, each representing a single application in a suite of programs.

The String[] Array

The String[] array in the main method signature is a parameter that’s filled by the JVM with all the arguments provided by the user on the command line. One example where a user might want to pass an argument to a program on the command line could be a choice of configuration file to use:

% java CriticalSafetyControlApp daytimeConfig.xml

Even though it doesn’t involve critical safety controls, let’s change up our “Hello World” program to look through its command-line arguments:

public class HelloWorldPrinter
{
    public static void main(String[] args)
    {
        for (String a : args) {
            System.out.println("Hello " + a);
        }
    }
}

If we pass three arguments on the command line, each one will be placed into the args array:

% javac HelloWorldPrinter.java
% java HelloWorldPrinter Alice Bob Carol
Hello Alice
Hello Bob
Hello Carol

If no arguments are provided on the command line, args will be an empty array. So, in this case, no greetings are printed:

% java HelloWorldPrinter

Unlike with the name main, there’s nothing special about the variable name args — using that name is simply convention. Nothing is stopping you from using a different variable name, expect the confusion you’d cause:

public class HelloWorldPrinter
{
    // PLEASE DON'T
    public static void main(String[] foo)
    {
        for (String f : foo) {
            System.out.println("Hello " + f);
        }
    }
}

The System.out Object

It’s easy to forget, just like with the HelloWorldPrinter class, that the System class is itself a class. It’s easy to forget because it’s in the part of the Java language that gets automatically imported into every project. You never need to write:

import java.lang.System;  // UNNECESSARY

public class HelloWorldPrinter {...}

If we dive into the Java API for the System class, we see that it has a static field that is public in accessibility called out. That is to say, the out object, being static, belongs to the System class itself.

From the API page for System, the out field is defined as:

public static final PrintStream out

This field definition tells us that System.out is an object of the PrintStream class. But, what use is that information to us? Let’s dive one layer deeper into the Java API documentation.

The PrintStream Class

Now that we’ve drilled down into the System class to see that System.out is a PrintStream object, let’s learn more about it. If we go to the Java API page for the PrintStream class, we can see what methods are available to us.

Of note for our first Java application, the PrintStream class has numerous overloaded println methods, such as:

public void println(String x)

It’s this instance method of the PrintStream object that produces our application’s output.

As a study exercise on the topic of overloaded methods, determine which println() method will be executed by a PrintStream object when different data types are given as arguments.

Summary

For a first program we learn as computer science students, there’s certainly a lot happening in Java’s version of “Hello World”. For most of the semester, I’m happy for students to think of a lot of the code in “Hello World” as “magic”. It’s just the stuff surrounding the code we actually care about.

But, as the end of an introductory term in Java approaches, it’s worth looking back at the first “Hello World” code we wrote. Of course it’s possible that, in your semester, you won’t have covered the meaning of all of the keywords in the code. But, see how many of them you can not only recognize, but also explain.

I also recommend you take the opportunity, while looking at the “Hello World” code, to review concepts like static fields (such as System.out), instance methods (such as println), and static methods (such as main). Finding examples of these types of fields and methods in the Java standard library can also be a good exercise to familiarize yourself with the extensive API documentation.

Java’s seemingly simple “Hello World” program has a surprisingly large number of study topics bunched together in just a few lines of code!

For more tips, and to arrange for personalized tutoring for yourself or your study group, check out Vancouver Computer Science Tutoring.