|












| |
Java Common Mistakes
- Accessing non-static member variables from static
methods (such as main)
Many programmers, particularly when first introduced to Java, have problems
with accessing member variables from their main method. The method signature
for main is marked static - meaning that we don't need to create an instance
of the class to invoke the main method. For example, a Java Virtual Machine (JVM)
could call the class MyApplication like this :-
MyApplication.main ( command_line_args );
This means, however, that there isn't an instance of MyApplication - it
doesn't have any member variables to access! Take for example the following
application, which will generate a compiler error message.
public class StaticDemo
{
public String my_member_variable = "somedata";
public static void main (String args[])
{
// Access a non-static member from static method
System.out.println ("This generates a compiler error" +
my_member_variable );
}
}
If you want to access its member variables from a non-static method (like
main), you must create an instance of the object. Here's a simple example of
how to correctly write code to access non-static member variables, by first
creating an instance of the object.
public class NonStaticDemo
{
public String my_member_variable = "somedata";
public static void main (String args[])
{
NonStaticDemo demo = new NonStaticDemo();
// Access member variable of demo
System.out.println ("This WON'T generate an error" +
demo.my_member_variable );
}
}
- Confusion over passing by value, and passing by
reference
This can be a frustrating problem to diagnose, because when you look at the
code, you might be sure that its passing by reference, but find that its
actually being passed by value. Java uses both, so you need to understand when
you're passing by value, and when you're passing by reference.
When you pass a primitive data type, such as a char, int, float, or double, to
a function then you are passing by value. That means that a copy of the data
type is duplicated, and passed to the function. If the function chooses to
modify that value, it will be modifying the copy only. Once the function
finishes, and control is returned to the returning function, the "real"
variable will be untouched, and no changes will have been saved. If you need
to modify a primitive data type, make it a return value for a function, or
wrap it inside an object.
When you pass a Java object, such as an array, a vector, or a string, to a
function then you are passing by reference. Yes - a String is actually an
object, not a primitive data type. So that means that if you pass an object to
a function, you are passing a reference to it, not a duplicate. Any changes
you make to the object's member variables will be permanent - which can be
either good or bad, depending on whether this was what you intended.
On a side note, since String contains no methods to modify its contents, you
might as well be passing by value.
- Null pointers are one of the most common errors that
Java programmers make. Compilers can't check this one for you - it will only
surface at runtime, and if you don't discover it, your users certainly will.
When an attempt to access an object is made, and the reference to that object
is null, a NullPointerException will be thrown. The cause of null pointers can
be varied, but generally it means that either you haven't initialized an
object, or you haven't checked the return value of a function.
Many functions return null to indicate an error condition - but unless you
check your return values, you'll never know what's happening. Since the cause
is an error condition, normal testing may not pick it up - which means that
your users will end up discovering the problem for you. If the API function
indicates that null may be returned, be sure to check this before using the
object reference!
Another cause is where your initialization has been sloppy, or where it is
conditional. For example, examine the following code, and see if you can spot
the problem.
public static void main(String args[])
{
// Accept up to 3 parameters
String[] list = new String[3];
int index = 0;
while ( (index < args.length) && ( index < 3 ) )
{
list[index++] = args[index];
}
// Check all the parameters
for (int i = 0; i < list.length; i++)
{
if (list[i].equals "-help")
{
// .........
}
else
if (list[i].equals "-cp")
{
// .........
}
// else .....
}
}
This code (while a contrived example), shows a common mistake. Under some
circumstances, where the user enters three or more parameters, the code will
run fine. If no parameters are entered, you'll get a NullPointerException at
runtime. Sometimes your variables (the array of strings) will be initialized,
and other times they won't. One easy solution is to check BEFORE you attempt
to access a variable in an array that it is not equal to null.
- Treating Strings as In/Out Parameters
Java's string class, java.lang.String, provides a good encapsulation of string
data. However, Java strings are (1) immutable, and (2) objects. Therefore,
they cannot be treated as simple character buffers; they must be treated as
immutable opaque objects. Sometimes, a student will attempt to treat a String
parameter to a method as if it were a character array passed by reference (as
in a C char array, or a C++ STL string object). This is a fairly subtle
mistake, but one which usually passes the compiler.
Mistake Example
public static void main(String args[]) {
String test1 = "Today is ";
appendTodaysDate(test1);
System.out.println(test1);
}
public void appendTodaysDate(String line) {
line = line + (new Date()).toString();
}
In the example above, the student is expecting to change the value of main's
local variable test1 by assigning a value to the parameter line in the
appendTodaysDate method. Of course, this won't work; the local value of line
will change, but the string test1 will be unaffected.
This mistake can come up if the student has not yet accepted the fact that (1)
Java objects are always passed by handle, and (2) Java strings are immutable.
As the instructor, you have to explain Java parameter passing, and emphasize
that String objects never change their value, but instead all String
operations merely create new String objects.
For the particular problem shown above, the fix is either to return a string
value from the method, or to pass a StringBuffer object instead of a String
object.
Corrected Example 1
public static void main(String args[]) {
String test1 = "Today is ";
test1 = appendTodaysDate(test1);
System.out.println(test1);
}
public String appendTodaysDate(String line) {
return (line + (new Date()).toString());
}
Corrected Example 2
public static void main(String args[]) {
StringBuffer test1 = new StringBuffer("Today is ");
appendTodaysDate(test1);
System.out.println(test1.toString());
}
public void appendTodaysDate(StringBuffer line) {
line.append((new Date()).toString());
}
- Using double data type in financial calculations results
in lost of precision. For more details refer to a detailed discussion
here.
- In Java, a single equal sign ( = ) is an entirely
different operator than a double equal sign ( == ). In most cases, use the
double equal sign when creating a loop or conditional statement and use the
single equal sign everywhere else. For example:
To compare a and b for equality, use a==b; (note the double equal sign).
Where b has the same value as a, use a=b; (note the single equal sign).
|