3. Basic program structure and flow#

This chapter deals with basic program structure and some flow control. Flow control (switch etc) will be described in-depth in Flow control .

3.1. Basic program structure#

As stated before, a Java program must have a main() method as starting point. This main() method needs to reside in a class, because all Java code needs to live inside a class.

This is the simplest possible app in

/**
 * The package declaration; it defines the namespace of this class
 * */
package snippets;

public class MostBasicApp {
    /**
     * This is a STATIC method, which means it is a class-level method and needs
     * no object/instance to be callable.
     * The return type is "void": it does not return anything.
     * @param args the command-line arguments are passed here as string array
     */
    public static void main(String[] args) {
        System.out.println("Basic App has started");
        System.out.println("...and ended");
    }
}

This is a very uninteresting app of course, since it doesn’t do anything. Let’s extend it with a bit of functionality. We’ll pass the program 2 arguments: one for age and one for user name. If no arguments are provided, we’ll print some usage information.

To pass command-line arguments within IntelliJ, you need to create or edit a run configuration. If you have run the main before (by clicking on the green triangle), you click on the toolbar run configurations box and select “Edit configurations”- see screenshot.

Run configuration

The only thing you need to do now is enter two “Program arguments”. Here, I filled out “Henk” and “49”, with a space between them.

Run configuration

An array (which is kind of a list) of String elements called args will be passed to main() as String[] args. This array will hold the command line arguments when next running the program, as demonstrated below.

public static void main(String[] args) {
    for (String arg : args) {
        System.out.println("arg = " + arg);
    }
}

This will output

arg = Henk
arg = 49

In a real terminal

In a real terminal you need to enter commandline arguments like this of course:
java -jar <my_app.jar> arg1 arg2

Here you have seen the first program flow control structure in action: the foreach loop. It is equivalent to for-loops in any programming language: it iterates a collection of some sort. Here the collection is an array. Note it does not have a counter variable; there is a different variant of the for loop for that.

Let’s introduce one other flow construct: decisions with if/else.

Suppose you want to give your user some uplifting message, depending on their age. First the age argument needs to be converted from String to int:

/**
  * Use indexing to access array elements
  */
String name = args[0];
/**
  * Parse String into int
  */
int age = Integer.parseInt(args[1]);
System.out.println("Hi " + name + ", your age is " + age);

Warning

All commandline arguments -also the ones that may look like numbers- enter your program as String variables in a String array.

Next, the choice of message needs to be made.

if(age < 18) {
    System.out.println("ahh the energy of youth");
} else if (age < 50) {
    System.out.println("nice to meet somebody in the prime of their life!");
} else {
    System.out.println("hey, don't worry - every day brings you closer to retirement");
}

These are the classic elements of the if/else decision block.

Finally, let’s bring a dedicated object into play: the message maker which will be responsible for serving messages based on the user age. The class looks like this:

package snippets;

public class MessageMaker {
    private final String name;
    private final int age;

    /**
     * Constructor makes it mandatory to instantiate with name and age arguments.
     * @param name
     * @param age
     */
    public MessageMaker(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void printMessage() {
        System.out.println("Hi " + name + ", your age is " + age);

        if(age < 18) {
            System.out.println("ahh the energy of youth");
        } else if (age < 50) {
            System.out.println("nice to meet somebody in the prime of their life!");
        } else {
            System.out.println("hey, don't worry - every day brings you closer to retirement");
        }
    }
}

And this is how you instantiate and use an object of such a class.

public class MostBasicApp {
    public static void main(String[] args) {
        String name = args[0];
        int age = Integer.parseInt(args[1]);

        /*A first object is instantiated and a method is called on it.*/
        MessageMaker messageMaker = new MessageMaker(name, age);
        messageMaker.printMessage();
    }
}

So, here we have an application consisting of two custom classes. Both source files are in the same package (namespace). The first is the so-called “main class” which is the entry point of the application: MostBasicApp in source file MostBasicApp.java. The main method receives the command-line arguments and parses one of them into an integer. Next, it instantiates a MessageMaker object and calls its printMessage() method.

Create an executable

If you want to have an executable jar it needs two things:

  1. A class with a public static void main(String[] args) method signature

  2. A manifest file in the jar with a reference to this main class; something like this:

    Manifest-Version: 1.0
    Main-Class: nl.bioinf.HelloWorld
    

    This can be generated when creating the jar (using Gradle) if you include this fragment in build.gradle:

    jar {
    manifest {
        attributes(
                'Main-Class': 'nl.bioinf.HelloWorld'
        )
    }
    

} ```

3.2. Summary#

You have seen the basic structure of a Java program. It needs at least one source file with one class. There needs to be a main() method of this signature to be executable as program:

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

Two flow control structures were shown: the for-each loop and if/else decisions:

//foreach
for(item : collection) {
    /*code block*/
}

//if/else
if(conditionIsTrue) {
    /*code block for condition*/
}
else if(alternativeConditionIsTrue){
    /*code block for alternative condition*/
}
else {
    /*default logic*/
}