J. Dalbey, 3/14/00
My experience is that Java is a difficult language for novices to learn programming, in part because the confusing syntax and semantics. Here is a list of difficulties that students encounter using Java in their first programming course. Almost all of these are problems that students don't struggle with in Pascal or Ada languages.
There are two categories: pitfalls and gotchas.
A Pitfall is when the program compiles without error but gives incorrect results. This is really bad and the cause of such famous disasters as the AT&T collapse of 1990.A Gotcha is just a confusing or obscure issue that often causes difficulties, but usually results in some error message (even if it is difficult to diagnose).
Java is case sensitive which causes needless headaches. For example, a student declared a global variable 'Alpha', and within a function declared a local variable 'alpha', but in the function body referred to 'Alpha'. The function compiled and produced incorrect results. Admittedly, the student violated guidelines for good variable names, but the case sensitivity of the language is not an aid to learning.
The keywords in the language are the obvious syntactical elements one might like to emphasize by making them upper case, but this is not allowed.
Integer division
The division operator is overloaded, thus 1 / 2 does not equal 0.5 as most students expect. Pascal has a separate operator, div, for integer division so students don't fall into this pitfall.
Loops without braces
Java allows loops without braces around the body. Almost every student falls into this trap at least once:
while (condition)
statement1;
statement2; //only first statement is in body
of loop
Students assume body statements are in the body. Similarly,
while (condition)
statement1; statement2
Both statements appear to be in loop, but only first is.
The above examples would not compile in other languages.
Decisions without braces
Same problem as above.
Null Body Loops
A loop with a null body is allowed to compile, e.g.
while (condition); // compiles ok, causes infinite loop
statement;
This error is very difficult for students to detect. The same problem occurs with "if" statements.
Ignoring a function value
A peculiarity of the Java language is that it lets you ignore the value returned by a value-returning function. For example, you could write the following statement in your program without any complaint from the compiler:
Math.sqrt(x); // return value ignored
When this statement is executed, the value returned by sqrt is promptly discarded. This function call has absolutely no effect except to waste the computer's time by calculating a value that is never used. This causes problems for students when they invoke their own methods but forget to use the return value ... the program compiles but gives wrong results.
Unexpected results from System.in.read()
System.in is an InputStream and the read() method definition says it returns an int. But calling System.in.read() does NOT return the integer you type at the keyboard.
Methods won't modify parameters of a primitive type
// Try to Add one to argument: compiler allows
it but it doesn't work
static private void Increment (int Number) {
Number = Number + 1; }
int Sum = 0;
Increment (Sum); // does NOT actually
increment
Array and String declarations
Arrays and Strings are indexed starting at zero, which is really bizarre. Who starts counting at zero? So naturally a student trying to extract the first character in a string will use the command
// trying to isolate the first character, but it actually gets the
second.
OneLetter = MyString.charAt(1);
Array and String declarations
Array declarations are weird: the last item of array int[35] Lucy is Lucy[34]. Go Figure.
Array indices must be integers and start at zero, so students struggle in a situation where the data in the problem are not integers: frequency count of characters is a classic example. For instance:
// Compiles, but sure doesn't do what the student expects.Increment-assignment
int[] Count = new int[26];
Count['A'] = 0; // causes run-time error
The statement: Total += 2;
increments Total by 2 is commonly miscoded as Total =+ 2;
which unfortunately DOES compile and simply assigns 2 to Total.
Type Casting a Character to an Integer
Students often expect that one could "convert" a character to an integer by type casting. This will compile, but doesn't give the results one might expect.
Char symbol = '7';
System.out.println((int) Symbol); // displays 55 not 7.
Implicit conversion of method parameters
You can pass a character parameter to a method with an integer argument, giving unexpected results.
String Comparison
Don't use equality operator to compare Strings. A statement which uses the equality operator to compare two Strings will compile but will not give the expected results.
Strings Lucy = "one";
Strings Linus = "one";
If (Linus == Lucy) // gives FALSE
This is particularly nasty, because it appears to work correctly, but it doesn't. The proper way to compare Strings is with the equals() method.
If (Linus.equals(Lucy))
Using Java references instead of values
In the code fragment here, d1 and d2 are not values, but references to values. Student's commonly err in thinking that because d1 and d2 "have the same date" that they should be equal. But the "if" statement below is never true.
Date d1 = new Date(25,11,100); // means Dec 25th 2000 (weird!)
Date d2 = new Date(25,11,100);
if (d1 == d2) // never true!
case without break
If you mistakenly forget to put a break after a case in a switch statement, it will compile and execute and give incorrect results. The case just falls through to the next case.
This is a big dangerous pitfall.
Variables of primitive types hold values; variables of class types hold references
Widget Lucy = new Widget("one");
Widget Linus;
Linus = Lucy; //makes both variables refer to the same object.
Linus.Set("three"); // Also sets Lucy to "three" ???? confusing
to beginners and causes unexpected results
Similarly, instance variables of a class type can be changed, even if declared private.
(See Savitch, pg 275 - 278)
Overloading occurs before automatic type conversion
If a class has overloaded methods
Public void set(int Age)
Public void set(double Weight)
And you call it with Lucy.set(6) when you meant 6.0, it sets the age
instead of the weight, because overloading happens before the 6 can get
converted to 6.0.
Braces are difficult to see because they are so narrow and require carefully scrutiny to determine which direction they point. Other languages use keywords such as BEGIN-END which stand out are are easy to find matching pairs.
Confusing symbols
The following symbols do not have obvious meanings and are often confusing. Other languages have more obvious keywords or clear symbols.
= means assignment not equality
== means comparison but who can remember to type the second equal
sign?
&& means logical AND not "more of"
|| means logical OR (why don't they just use keyword OR?)
! means logical NOT not emphasis (exclamation point)
+ can mean addition or concatenation
\n who knows what these mean?!
++
+=
Omitting the default constructor
If your provide at least one constructor definition, java won’t provide the default constructor. This is easy to forget - however it will be caught by the compiler, but just confusing tofigure out.
Inconsistent semantics
The use of the "private" keyword is inconsistent. It works in some places, but not others. It may NOT be used on any declaration, only in specific places. It can't be used inside a method. Students frequently do something like the following, and the error message is very misleading.
public void SadMethod ( )
{
private int grumpy;
// keyword "private" not allowed here
Produces this misleading compiler error:
'}' expected.