This section describes common error messages and how to interpret them. The examples used are very simple and are there only to demonstrate a point, not to be particularly useful. An important point to remember when fixing errors is start with the first few errors, fix them and then try to recompile. Sometimes you find fixing the first couple of errors will fix several others further down in the list - although occasionally it can generate more!
1. public class JavaErrors 2. { 3. public static void main(String[] args) 4. { 5. // calculate the area of a rectangle (width * height) 6. int width = 100; 7. int height = 50; 8. 9. System.out.println("The area is " + area); 10. } 11. }
The code above generates the following error message:
JavaErrors.java:9: cannot resolve symbol symbol : variable area location: class JavaErrors System.out.println("The area is " + area); ^ 1 error
The first thing to do is don't panic. Look at each line of the error message:
JavaErrors.java:9: cannot resolve symbol
This tells you the following information:
filename:line number: error description
According to the error message, the error is in JavaError.java
on line 9
. But what does cannot resolve symbol
really mean? Basically the compiler has come across something that it has
never encoutered before as part of any declaration. What is it that
hasn't been declared? Take a look at the next line.
symbol : variable area
This tells us that it is a symbol
that hasn't been declared. A
symbol is a variable name, a class name or a method name. In this case it
is a variable
called area
. From the first line we
can now see that it is the area
variable that has not been
declared. Before we fix the problem let's take a look at the rest of the
message.
location: class JavaErrors System.out.println("The area is " + area); ^
This tells us that it is in the JavaErrors
class. Remember
that sometimes the error may have occurred in an inner class so the
location is not always the same as the filename.
The important thing is that it shows the line of code where the error occurred and even indicates using the "^" symbol the possible cause of the problem on that line.
Okay. Now we know that we are using the variable area
on the
given line and that the compiler doesn't recognise it. We can work out that
the reason it doesn't recognise it is because we haven't declared it. If we
declare the variable, that should fix the problem.
Here's the solution with the new line in bold:
1. public class JavaErrors 2. { 3. public static void main(String[] args) 4. { 5. // calculate the area of a rectangle (width * height) 6. int width = 100; 7. int height = 50; 8. 9. int area = width * height 10. 11. System.out.println("The area is " + area); 12. } 13. }
Let's say we make another mistake as we add the new line in the above solution and we forget to include the semicolon. This happens quite often. What's the error message?
JavaErrors.java:8: ';' expected int area = width * height ^
That's pretty easy to understand. Again the first line tells us the filename, the line number, and the error description even says something useful! In this case a semicolon is expected. To make things even clearer it shows us the problem line and indicates with the "^" symbol where the semicolon should be.
Take a look at the next example.
1. public class JavaErrors 2. { 3. public static void main(String[] args) 4. { 5. System.out.println("Hello world!); 6. } 7. }
The code in example 2 generates the following error messages:
JavaErrors.java:5: unclosed string literal System.out.println("Hello world); ^ JavaErrors.java:5: ')' expected System.out.println("Hello world); ^ 2 errors
Now we are getting used to the format of the error messages we can
see that the error description says unclosed string literal
.
But what does this mean? In this case all it means is that we have missed
the closing quote symbol (").
But what about the second error? Sometimes the java compiler can get confused when certain mistakes are made. This is one of those cases. It is also the reason why you should fix the first few errors first and then try to recompile. If you close the String and recompile you should find you get no errors.
Often you will find an error is generated because of a simple typo. Java is case sensitive so it is important you get it right. This type of error is demonstrated in example 3.
1. public class JavaErrors 2. { 3. public static void main(String[] args) 4. { 5. System.out.Println("Hello world!"); 6. } 7. }
The code in example 2 generates the following error message:
JavaErrors.java:5: cannot resolve symbol symbol : method Println (java.lang.String) location: class java.io.PrintStream System.out.Println("Hello world");
OK, it's another cannot resolve symbol
but this time the
symbol is method Println (java.lang.String). In example 2 it
was a variable, but here it is a method. Just briefly
look at the location line. It's telling us that we are trying to call the
Println
method for an object of type
java.io.PrintStream
. This is a standard java class so we can
look at the Java API to see what methods are available.
Back to the error. As before cannot resolve symbol
means the
java compiler cannot find the symbol it shows you on the symbol line. In
this case it cannot find a method called Println
for the object
out
. This is true, there is no such method, what we meant was
println
with a lowercase p. Fix this and jobs-a-good-un.
You should be aware that a similar error message would have been generated
if you had misspelt println
.
A related error to the kind described above is calling a method with the wrong parameters. There are several ways in which the parameters may be wrong:
1. public class JavaErrors 2. { 3. public static void main(String[] args) 4. { 5. Integer simpleInt = new Integer(1,2); 6. System.out.println(simpleInt); 7. } 8. }
The code in example 4 generates the following error message:
JavaErrors.java:5: cannot resolve symbol symbol : constructor Integer (int,int) location: class java.lang.Integer Integer simpleInt = new Integer(1,2); ^
Once again it's cannot resolve symbol
, and this time the
symbol is a constructor. So what can't the compiler find this time?
It can't find a constructor in the Integer
class that takes
two int
values. Check the Java API to see what constructors
are available. There are at least two:
Integer(int value)
- which creates an Integer
object that represents the specified value.Integer(String value)
- which creates an Integer
object that represents the value represented by the String.A constructor which takes one int
exists, but a constructor
that takes two doesn't, hence the error message. Remove one of the
int
arguments and the problem will be fixed.
1. public class JavaErrors 2. { 3. public static void main(String[] args) 4. { 5. Integer simpleInt = new Integer(2.5); 6. System.out.println("My Integer has a value "+simpleInt); 7. } 8. }
The code in example 5 generates the following error message:
JavaErrors.java:5: cannot resolve symbol symbol : constructor Integer (double) location: class java.lang.Integer Integer simpleInt = new Integer(2.5); ^
This is similar to the problem with example 4, this time we have the right
number of parameters but the one we are passing in is of the wrong type.
A constructor which takes a double
argument doesn't exist so
we get the error message. Change the value 2.5
to 2
and it should fix the problem. But what happens if the value I want to pass
to the constructor is held in a variable of type double
? How
can I convert it to an int
? Take a look at
casting errors.
Casting errors can occur when we try to convert a primitive or object of one type into a primitive or object of another type. Some types of conversion just aren't allowed, and if you try to perform an illegal conversion you will get errors.
let's change the code in example 5 above so that the value is held in a
primitive double
, and we want to create an Integer
object using the Integer(int)
constructor.
1. public class JavaErrors 2. { 3. public static void main(String[] args) 4. { 5. double doubleValue = 2.5; 6. Integer simpleInt = new Integer(doubleValue); 7. System.out.println("My Integer has a value " + simpleInt); 8. } 9. }
The code in example 6 has the same problem as example 5, and generates a
similar error message. We can't pass a double
to an
Integer
constructor, because no such constructor exists! So
what can we do? Let's try casting the double
to an
int
. Change the line:
Integer simpleInt = new Integer(doubleValue);
in example 6 to:
Integer simpleInt = new Integer((int)doubleValue);
The new bit, the cast, is highlighted in bold. But what happens
when you run the program; what will be output for the value of the
Integer
? Will it be 2.5 or will it be 2?
The int
primitive type and the Integer
class can
only store whole number values. Casting the double
to an
int
causes the value of that double
to be truncated
(or rounded down) to the nearest int
. So in this case the
output will be:
My Integer has a value 2
This is something you have to be careful with when casting from one primitive or object to another. However, it's not normally something that the compiler will warn you about. This sort of problem will be covered later in the section on Runtime Errors.
We haven't actually seen a compile time casting error yet - let's create one.
1. public class JavaErrors 2. { 3. public static void main(String[] args) 4. { 5. int intValue = 100; 6. String myString = (String)intValue; 6. System.out.println("The current int value is " + myString); 7. } 8. }
The (somewhat convoluted) code in example 7 generates the following error message:
JavaErrors.java:6: inconvertible types found : int required: java.lang.String String myString = (String)intValue; ^
This looks a bit different (finally something other than cannot
resolve symbol
!). The error description is inconvertible
types
, which means that the value we are trying to cast isn't
compatible with the type that we are trying to cast it to. There are lots
of rules governing casting, but one fundamental principle is that you cannot
cast a primitive type to an object type, or vice versa. To get around this
problem, we need a means of creating a String
object from
an int
primitive. If you look at the Java API for the
String
class, you can see that the static method
valueOf(int i)
does what we want. We can pass an
int
into the valueOf
method and get an appropriate
String
object back. The code in example 7 then becomes:
1. public class JavaErrors 2. { 3. public static void main(String[] args) 4. { 5. int intValue = 100; 6. String myString = String.valueOf(intValue); 6. System.out.println("The current int value is " + myString); 7. } 8. }
Java has two types of exceptions, checked and unchecked exceptions. Checked
exceptions are the ones that you have to deal with in your code
wherever they may occur, either by using a try
block, or by
including a throws
clause in the method signature. Unchecked
exceptions are generally those which could occur so frequently in any
normal piece of code that it would be impossible to try and handle them.
All unchecked exceptions must be direct or indirect subclasses of
RuntimeException
, this is what tells the compiler that a
particular exception is exempt from the rules governing checked exceptions.
If a RuntimeException
occurs, it will not normally be handled
within the code, and so will cause your program to crash. However, a
RuntimeException
is usually a sign that there is an error in
your code, so you shouldn't try and handle them; instead you should change
your program to prevent the exception from occuring. Two of the most
common types of RuntimeException
are described below.
This exception is thrown when the index value used to access an array is not valid. When access the elements of an array, the index value must be between 0 and the size of the array minus one.
1. public class JavaErrors 2. { 3. public static void main(String[] args) 4. { 5. int[] myArray = new int[3]; // an int array with size = 3 6. 7. myArray[0] = 1; // OK 8. myArray[1] = 2; // OK 9. myArray[2] = 3; // OK 10. myArray[3] = 4; // Error - index 3 is invalid 11. } 12. }
In the code above, the line:
myArray[3] = 4; // Error - index 3 is invalid
will generate an ArrayIndexOutOfBoundsException
similar to the following:
java.lang.ArrayIndexOutOfBoundsException at JavaErrors.main(JavaErrors.java:10)
From the above error message, you can determine that the error occurred on line
10 of the file JavaErrors.java
. Checking this line, you can see that
the index used is equal to the size of the array and is therefore not
valid.
If an object reference is null
, it means that no value has yet
been assigned to that reference, i.e. it has been declared, but not
initialised. To read more about declaration and initialisation, look
on the miscellaneous information page.
A NullPointerException
occurs if you try to use a null reference
as though it were a reference to an actual object, e.g. if you try and call
a method for the object.
1. public class JavaErrors 2. { 3. public static void main(String[] args) 4. { 5. int[] myArray = new int[3]; // an int array with size = 3 6. int[] anotherArray; // an array that has been declared, 7. // but not initialised, so it's null 8. myArray[0] = 1; // OK 9. myArray[1] = 2; // OK 10. myArray[2] = 3; // OK 11. 12. anotherArray[0] = 4; // Error - anotherArray is null 13. } 14. }
The code in example 9 will generate a NullPointerException
similar to
the following:
java.lang.NullPointerException at JavaErrors.main(JavaErrors.java:12)
The second array variable, named anotherArray
, has not been
initialised, so attempting to access any of its elements will result in this
kind of exception.
If a NullPointerException
occurs within your program, look at the
line indicated in the error message. Often there will only be one object reference
on the line, in which case you know that is the null
reference. If
there are more references, you need to establish which one is null
.
Once you have found the null
reference, trace the code back to find
where it should have been initialised, and fix the problem.
Another common mistake which causes NullPointerException
s is shown
in the next example.
1. public class JavaErrors 2. { 3. private String myName; 4. 5. public JavaErrors() 6. { 7. String myName = "B.Wilkins"; 8. } 9. 10. public int getNameLength() 11. { 12. return myName.length(); 13. } 14. 15. public static void main(String[] args) 16. { 17. new JavaErrors(); 18. } 19. }
The line in italics in example 10 will generate a NullPointerException
,
but it's actually the line in bold where the mistake has been made. This is a
problem with object scope. The String
myName
is a data member of the class. It has been declared at the
top of the class but not initialised. Normally, you would initialise it in
the constructor, which is what's supposed to happen here. However,
instead of referencing the instance variable myName
and initialising
it like this:
myName = "B.Wilkins";
what actually happens in the constructor is rather different. A new
variable named myName
is declared and initialised. This variable is
local to the constructor, so that when the constructor has finished, this variable
is lost. At no point is any change made to the instance variable
myName
, which means that it will still be null
when the
constructor has finished. Consequently, attempting to call the length()
method on line 12 will cause a NullPointerException
. The solution is
to change line 7 to the one shown above.
An infinite loop is a loop that never ends, causing your program to run on and on until you kill it. The compiler cannot detect infinite loops and will not generate any warning messages. It is up to you to prevent them from occurring. Common causes of infinite loops include:
Failure to increment the loop counter.
int i = 0; while (i < 10) { System.out.println("Counter is at " + i); }
The loop counter i
is never changed, so the test (i < 10)
always evaluates to true and the loop never ends.
The loop relies on the result of some calculation to end and this calculation contains an error.
As well as having problems with loop control structures, i.e.
while
and for
loops, you can also create circular
references within your program which mean that it will never terminate.
1. public class JavaErrors 2. { 3. public static void main(String[] args) 4. { 5. doA(); 6. } 7. 8. public static void doA() 9. { 10. doB(); 11. } 12. 13. public static void doB() 14. { 15. doA(); 16. } 17. }
This example will bounce backwards and forwards between the two methods
doA()
and doB()
and never finish. Obviously this
is a very silly and simplistic example, but in larger projects it's possible
to get into this sort of situation without it being quite so obvious.
Skipping code is generally caused by adding a semi-colon at the end of a
control statement (if
, while
, for
, etc.,).
The resulting code is legal Java, so the compiler won't generate any warnings,
but it will not behave how you expect it to.
1. public class JavaErrors 2. { 3. public static void main(String[] args) 4. { 5. int i = Integer.parseInt(args[0]); 6. 7. if (i > 100); 8. System.out.println("Arg value is greater than 100"); 9. } 10. }
No matter what command line argument is passed to this program, it will
always print the message saying that the value is greater than 100. To
understand this, you need to remember the rules for what part of the
code is governed by a control statement. If the first non-whitespace character
after the control statement is an opening brace, then the statement governs
the entire block of code up to the closing brace. Otherwise, the control
statement governs the next statement, i.e. up to the first semi-colon.
Because the first character after the if
statement on line 7 is a
semi-colon, the if
statement governs the empty statement between
the closing parenthesis and the semi-colon, i.e. if the value of i
is greater than 100, it does nothing. The following statement is then executed
every time, because it is outside the control structure.
N.B. This sort of mistake can also easily generate an infinite loop, as in the example below:
1. public class JavaErrors 2. { 3. public static void main(String[] args) 4. { 5. int i = 0; 6. 7. while (i < 10); 8. { 9. System.out.println("i = " + i); 10. i++; 11. } 12. } 13. }