Archive for March, 2017

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

22/03/2017

 

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

Advertisements

Pushing Java Envelope – Part 1: Java Class File

03/03/2017

 

 

For a few days, I am working on Java to get OCA certificate. To be honest, my initial thinking was that, with a little bit of study, I would easily pass it. However, when I started to practice, I understood that the exam tries to trick you while asking fundamentals of Java. It also makes us double think on the aspects of the programming language that we all took for granted. As I dive deeper, I found many things that Java permits but we do not use that much. In this post, I will start with basics and present codes that emphasis each point.

Java Class File

In Java, every application has one or many classes, since everything depend on them. The basic class file presents the fields, methods of the class. Also, we can learn how to initialize an object of that class by the same file. The interesting point is, there may be more than one class in a file. I am not talking about inner classes. What I mean is, in the same file, there can be more than one class definition independent of each other. Here is an example MultipleClasses.java file content that is perfectly valid:

public class MultipleClasses {
  int a = 5;
  private Helper helper = new Helper();

public static void main(String[] args) {
MultipleClasses mc = new MultipleClasses();
System.out.println(mc.helper.getB());
}
}
class Helper {
  private int b;
 
public int getB() {
return this.b;
}

public static void main(String[] args) {
System.out.println("How may I help you?");
MultipleClasses mc = new MultipleClasses();
System.out.println(mc.a);
}
}

Now let’s move step by step and see what happens. First, compiling the code. Since the file name is MultipleClasses.java, we will run:

javac MultipleClasses.java

Multiple Class Files

It compiles and generates 2 .class files! One is MultipleClasses.class and the other one is Helper.class. If we had gone with the inner classes, what we would have gotten was again two classes but the latter one being MulitpleClasses$Helper.class. Here we understand that the two classes in the same file are totally different classes. We can add as many classes as possible in the same file, generating .class files for each. This result is exactly the same when we have files dedicated to each class. Each class has its own main() method so we can run MultipleClass and Helper with the java command.

When we run MultipleClass, the main() of that class takes control. It creates a MultipleClasses object. For that, the control is transferred to the instance initializer. We see that the package-private field a is set to integer literal 5. Also, another Helper object is created and set to the private field helper. That means, the control is now inside Helper instance initializer. There, we only reset the private integer field b to 0 and return to the MultipleClasses instance initializer. Since there is nothing to be left in the MultipleClasses instance initializer, it returns to the main() method.

The objects are ready so we can print the b field of helper. One of the important points here is that, we cannot access private fields of helper object from MultipleClass. There will be a compile-time error if we try to directly access the private b field inside the Helper object from MultipleClass object. That’s why I added the public getB() method to Helper class. We expected to and now see a 0 (zero) on the screen.

MulipleClasses Stack

Following the same procedure, we can also generate the output of java Helper command. We again start with the main() method but this time, it is the main() method of Helper class. It prints “How may I help you?” in a new line first. After that, it creates a new instance of MultipleClasses. The control is transferred to its instance initializer. It sets 5 to package-private field a. Again, another Helper object is created and set to the private field helper. That means, the control is now inside Helper instance initializer. There, we only reset the private integer field b to 0 and return to the MultipleClasses instance initializer. It has nothing else to do, just returns back to main() method of Helper class. Here we will print the a field of newly created MultipleClasses object, which is named as mc. The small but significant change is that, for that field we DO NOT NEED a public getter to access. That is because that field is package-private.

Helper Running Stack

So the output of the Helper will be “How may I help you?” followed by 5 (five).

Multiple Java Runs

 

Restrictions

In Java, we can make the top-level classes either public or package-private (i.e. by not writing anything before class className). With more than one top-level classes in the same file, all classes can be package-private. In that case, we can give ANY name to the class file. I mean, really ANY NAME WE WANT. It does not have to be a class name. Java does not care the name of the java class file when there is no public class inside the .java file. The following, slightly modified example is just OK with the file name What.java

class MultipleClasses {
  int a = 5;
private Helper helper = new Helper();

public static void main(String[] args) {
MultipleClasses mc = new MultipleClasses();
System.out.println(mc.helper.getB());
}
}
class Helper {
private int b;

public int getB() {
return this.b;
}

public static void main(String[] args) {
System.out.println("How may I help you?");
MultipleClasses mc = new MultipleClasses();
System.out.println(mc.a);
}
}

As you can see, there is NO class named as What but the file name is What.java. 

If we want to make the classes inside the Java file public, that drastically changes everything. First, there can only be one public class per file. We cannot make both MultipleClasses and Helper public. Also, the public one now dictates the name of the Java class file. The very first example above illustrates that case. MultipleClasses is public so the name of the file must be MultipleClasses.java.

Packaging

There are many clues that takes us to the point that these classes inside the same class file are actually classes in the same package. To verify this, I created two more simple classes with their own class files. One of them, InPackage, will share the same package with MultipleClasses and Helper. The other one, OutPackage, will be totally out of their package. Also, I will modify MultipleClasses and Helper, so that each of them will try to access InPackage class.

There are two packages: experiment and other. MultipleClasses and Helper classes are in the same file, MultipleClasses.java. They are also in the experiment package. They both initialize an instance of InPackage class, which is in the InPackage.java file. The InPackage class also initializes one object from each. The key point is that, none of the java files import anything. That’s all below:

package experiment;
public class MultipleClasses {
int a = 5;
private Helper helper = new Helper();

public static void main(String[] args) {
MultipleClasses mc = new MultipleClasses();
System.out.println(mc.helper.getB());
InPackage inPackage = new InPackage();
System.out.println(inPackage.c);
}
}
class Helper {
private int b;

public int getB() {
return this.b;
}

public static void main(String[] args) {
System.out.println("How may I help you?");
MultipleClasses mc = new MultipleClasses();
System.out.println(mc.a);
InPackage inPackage = new InPackage();
System.out.println(inPackage.c);
}
}

The code for the simple InPackage class is here:

package experiment;
class InPackage {
int c = 3;
  public static void main(String[] args) {
Helper helper = new Helper();
System.out.println(helper.getB());
MultipleClasses mc = new MultipleClasses();
System.out.println(mc.a);
}
}

Packages

As you can see, these three classes belong to the same package. My aim is to show that, these can access each other without importing any other package. After comping two files, I run each class and get the outputs. You can see them below:

3 Classes Run

Without importing any other class, we can safely use each of them in their respective main() methods. See also that, both MultipleClasses and Helper access directly to the package-private field (c) of InPackage class, whereas the InPackage class can access the package-private field (a) of MultipleClasses. These show that all three classes belong to the same package.

Now let’s turn out attention to the OutPackage class. It exists inside the package named other. I will compile this class first without an import statement, then with it.

package other;
// import experiment.*;
public class OutPackage {
  public static void main(String[] args) {
Helper helper = new Helper();
System.out.println(helper.getB());
MultipleClasses mc = new MultipleClasses();
System.out.println(mc.a);
  }
}

When we comment out the import statement, the code does not compile since it cannot find anything about MultipleClasses and Helper.

Without Import Statement

When we import those two classes, the compiler still complains but for a different reason. It now knows about the classes but it also knows that Helper class is only package-private, which prohibits its direct use from a different package.

With Import Statement

Hence, we are sure that putting more than one class inside a single .java file makes them share the same package.