Pushing Java Envelope – Part 2: public static void main(String[] args)

 

Every Java program starts with the main() method. When the command java (or javaw) runs with a class name, it finds the byte code representation of that class (most probably the .class file), makes the necessary preparations, does some validation work and gives the control to the main() method. It is not an ordinary method though. It must conform some strict and a few flexible properties. These are:

  • must have a name main in all lowercase letters
  • must be public
  • must be static
  • must return nothing (i.e. void)
  • must take only one parameter and it must be a String array

Under the guidance of these, a very simple and valid main() method can be defined as:

public static void main(String[] args) {
System.out.println("I am the main: " + args.length);
}

The reason for being named as main() is most probably historic. The ancestors of Java programming language are C and C++. Their designated start-ups are the main() functions, hence Java also kept that tradition. To make the method visible from anywhere, the identifier public is set. These are all preferences. The starting method may have a very different name or it can be set to a different access modifier. Those were decided by the creators of Java. However, the identifier static has a logic behind it. Assume that we do not make it static. This means that, every object for that class has it’s own main() method and the class has none for itself. When we run java with the class name, java has information only about the class, not the objects. Besides, there are no objects at that time. So which main() method should be used? To avoid such ambiguity, the designers of Java make the starting main() method a feature of the class, not the objects, by adding the static identifier.

The order of appearance of the access modifier public and identifier static are interchangeable. It is almost universal to use public before static, but the following code is also valid.

static public void main(String[] args) {
System.out.println("I am the main: " + args.length);
}

The return type, void, must be just before the main() method name however. The following code won’t compile because the return type is not in it’s proper place.

void public static main(String[] args) {
System.out.println("I am the main: " + args.length);
}

Void public static

Since the input type must be an array of Strings, any valid array syntax is OK. So we can safely compile the following codes.

public static void main(String... args) {
System.out.println("I am the main: " + args.length);
}
public static void main(String args[]) {
System.out.println("I am the main: " + args.length);
}

Java defines the method signature as

  • the name of the method
  • the types of the parameters

The method signature does not contain anything about the parameter names. Therefore, the name of the input parameters is not important. Any valid Java identifier can be used. In the code below, otherThanArgs parameter name is used and accessed.

public static void main(String[] otherThanArgs) {
System.out.println("I am the main: " + otherThanArgs.length);
}

Although any main() method can conform these requirements, the main() method that will be run when java runs must also return the type void. If not, the compiler won’t give any errors because it will treat that like any other method. The following code compiles perfectly.

public static int main(String[] args) {
System.out.println("I am the main: " + args.length);
return 0;
}

When this is run by java, it will complain that the main() method must return void, as in here:

NonVoidReturn

As another case, it must accept String array as its only parameter. Any other type is strictly prohibited in run-time. For example, when we supply integer array as the only parameter, again, compilation will succeed, but when running, we will be informed that there is no suitable main() method to be started.

public static void main(int[] otherThanStringArray) {
System.out.println("I am the main: " + otherThanStringArray.length);
}

Main int

Actually, all these imply that the main() is a very unique case of any generic method. If we want it to be run with java command, we must obey the very first rules presented above. If not, we are free to design it anyhow we like, since main is NOT a keyword in Java. In either case, we can call main() method as any other method. In the following example, the overloaded main() methods in class DifferentMainMethods are called from another class OtherClassMainCaller

public class OtherClassMainCaller {
public static void main(String[] args) {
System.out.println("I am the other main");
DifferentMainMethods.main(args);
DifferentMainMethods.main(new int[] {1, 2, 3});
}
}

public class DifferentMainMethods {
public static void main(String[] args) {
System.out.println("I am the main: " + args.length);
}

public static void main(int[] otherThanStringArray) {
System.out.println("I am the main: " + otherThanStringArray.length);
}
}

Let’s move over the code step by step. When the OtherClassMainCaller is run with the parameters “get ready for the action”, the main() method of it starts to run. It prints “I am the other main”. Later, the control is transfered to the main(String[]) method of class DifferentMainMethods. Since there are two classes of the same name in that class, I explicitly show the parameters. In fact, this method is the one if DifferentMainMethods was called from command line. It prints “I am the main: ” and the number of parameters it is supplied, which is 5. It is done, so returns back to main() of OtherClassMainCaller. Now, this time, the main(int[]) method of DifferentMainMethods is called. It gets an integer array of three elements. So, it writes “I am the main: ” and 3. Since there is no more instructions, the program terminates. The result on the secreen is like this:

DubleMainCaller

The main() method is also so similar to other methods that it may even throw exceptions.

public class ExceptionThrowingMain {
public static void main(String... args) throws Exception {
System.out.println("Watch out!");
throw new Exception();
}
}

Here, the main() method artificially throws a checked exception. I preferred checked one but we can also throw an unchecked one, like NullPointerException. Running this will result the following output, as expected.

Throws

Throwing an exception also means there is a way to catch it. In another class, ExceptionCatchingMain, I call the very same main() method of ExceptionThrowingMain and caught the exception.

public class ExceptionCatchingMain {
public static void main(String[] args) {
try {
System.out.println("I will catch.");
ExceptionThrowingMain.main(args);
} catch (Exception ex) {
System.out.println("Here is the exception.");
}
}
}

 Running this will first print “I will catch.” Then, the other main method will print “Watch out!” and throw the exception. Since the main() method of ExceptionCatchingMain waits for it, it will print the last line, which is “Here is the exception.”

 

Catches

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s


%d bloggers like this: