In last week’s post I looked at the acronym “RTFM”. This stands for “Read the Fabulous Manual”, with the “F” being replaced with friendly, fine, fantastic, famous or any other word starting with an appropriate F.
There is a lesser-known, but similar acronym “RTFS” – “Read the Fabulous Screen”. In this post, I’ll be looking at the acronym specifically from the perspective of the output of the Java compiler.
Java Compiler Messages
Coming from a C/C++ background, one of the things that really struck me when I started coding in Java was the quality and clarity of the compiler error messages. In general I found them much easier to read and understand than the C/C++ compiler messages that I was used to. It could have been from growing maturity and coding experience, but I’m convinced that the Java compiler messages are fantastically useful, and deserve to be read carefully, i.e. “RTFS”. They point you close to the exact location of the error, including the line number and column.
A Simple Example
Let’s look at a small Java program similar in size to the standard “Hello, world” class.
public class ExampleClass {
public static void main (String args[]) {
int x;
System.out.println("x = " + x);
ExampleClass obj = new ExampleClass();
System.out.println(obj);
}
} // end of class
Nothing exotic or complicated about this class definition.
Let’s say that when we save this file, we make a spelling mistake and save it as ExamplClass.java
. Easy enough to do. What’s the error message when compiling ExamplClass.java
?
ExamplClass.java:4: error: class ExampleClass is public, should be declared in a file named ExampleClass.java
public class ExampleClass {
^
1 error
The message is straightforward and plain. We know that public classes must be saved in a file with the identical name of the class. And to put the cherry on the cake, the ^
points to the word class
.
So we rename the file to ExampleClass.java
and recompile.
Now another error message pops up:
ExampleClass.java:6: error: variable x might not have been initialized
System.out.println("x = " + x);
^
1 error
Again, the compiler does a sterling job pointing you to the right line number (6) and column (where the caret points), and tells you that variable x might not have been initialized
. Ahh! You remember that all local variables are created on the stack and are not initialised. So you assign a suitable value to x
and recompile. Success eventually!
An Override Error
The last line in the main()
method is System.out.println(obj);
Clearly we wanted to print some information about the object. Behind the scenes the toString()
method of the Object
class is called. If we want to override this toString()
method, we can easily do it as follows:
@Override public String toString() {
return "I'm an ExampleClass object";
}
What if we made another typo, and spelt toString()
with a capital letter T
as in:
@Override public String ToString() {
return "I'm an ExampleClass object";
}
The error message is again very obvious and points you directly to the culprit:
ExampleClass.java:12: error: method does not override or implement a method from a supertype
@Override public String ToString() {
^
1 error
A Few More Errors
The next two coding errors generate a lot of output from the compiler, so be warned.
Let’s say we forget the opening curly brace on the first line of the class definition.
public class ExampleClass // missing opening brace
The compiler output is the following:
ExampleClass.java:2: error: '{' expected
public class ExampleClass
^
ExampleClass.java:4: error: class, interface, enum, or record expected
public static void main (String args[])
^
ExampleClass.java:7: error: class, interface, enum, or record expected
System.out.println("x = " + x);
^
ExampleClass.java:9: error: class, interface, enum, or record expected
ExampleClass obj = new ExampleClass();
^
ExampleClass.java:10: error: class, interface, enum, or record expected
System.out.println("obj = " + obj);
^
ExampleClass.java:11: error: class, interface, enum, or record expected
}
^
ExampleClass.java:13: error: class, interface, enum, or record expected
@Override public String toString() {
^
ExampleClass.java:15: error: class, interface, enum, or record expected
}
^
8 errors
Lots of errors, but only the first one matters. Often the first error causes a cascade of what appear to be erroneous error messages.
The compiler again points you to the correct line number (2) and column (where the caret points):
ExampleClass.java:2: error: '{' expected
public class ExampleClass
^
Let’s say we forget the opening curly brace on the main()
method.
public static void main (String args[]) // missing opening brace
Again, a flood of error messages. This is a little more difficult to interpret. The first error says the compiler is expecting a semi-colon: error: ';' expected
. Obviously we know that we don’t put a semi-colon after a method header unless it’s an abstract method, so that’s a big clue.
ExampleClass.java:4: error: ';' expected
public static void main (String args[])
^
ExampleClass.java:7: error: <identifier> expected
System.out.println("x = " + x);
^
ExampleClass.java:7: error: illegal start of type
System.out.println("x = " + x);
^
ExampleClass.java:10: error: <identifier> expected
System.out.println("obj = " + obj);
^
ExampleClass.java:10: error: illegal start of type
System.out.println("obj = " + obj);
^
ExampleClass.java:13: error: class, interface, enum, or record expected
@Override public String toString() {
^
ExampleClass.java:15: error: class, interface, enum, or record expected
}
^
7 errors
The last two lines here (and just about all the lines of the previous errors) were error: class, interface, enum, or record expected
. This is a clear indication that you’re missing an opening brace somewhere important.
If we leave out a closing brace, we’ll normally get an error along the lines of :
ExampleClass.java:16: error: reached end of file while parsing
}
^
1 error
An Error Running the Compiler
I’m assuming here that we are compiling from the command line. I know most developers use an IDE of some description, but all IDEs capture the output of the javac
compiler. So the compiler error messages will be the same.
There are some errors that the IDE prevents you from making, such as forgetting to add the .java
extension to the filename. Let’s say we forget the extension when compiling from the command line:
C:\dev\ExampleClass>javac ExampleClass
error: Class names, 'ExampleClass', are only accepted if annotation processing is explicitly requested
1 error
This is a slightly less understandable error message, but once you read and think about it a bit, the compiler has told you that you haven’t passed it a file name, but rather the class name.
Ending Off
From all of these examples, it should be fairly obviously that if we just take the time to read the screen carefully, we should be able to solve all of our compilation errors.
In another post, I’ll look at runtime errors and the dreaded stack trace.
What do you think about RTFS? Share your comments and Java experiences.
Stay safe, and I’ll see you next week!