2.3 Final Parameters
Just when you think
it's safe to hit Compile, you can go even further
with finals. To illustrate,
suppose you hire a new developer and, while adding a new feature, he
decides to make a little change to the equation2(
) method from Example 2-4. The changes he
makes are shown in Example 2-9.
Example 2-9. Danger of nonfinal parameters
package oreilly.hcj.finalstory;
public class FinalParameters {
public double equation2(double inputValue) {
final double K = 1.414;
final double X = 45.0;
double result = (((Math.pow(inputValue, 3.0d) * K) + X) * M);
double powInputValue = 0;
if (result > 360) {
powInputValue = X * Math.sin(result);
} else {
inputValue = K * Math.sin(result);
}
result = Math.pow(result, powInputValue);
if (result > 360) {
result = result / inputValue;
}
return result;
}
}
The problem is that the new guy changed the value of the parameter
passed in to the method. During the first if
statement, the developer made one little mistake梙e typed
inputValue instead of
powInputValue. This caused errors in the
subsequent calculations in the method. The user of the function
expects certain output and doesn't get it; however,
the compiler says that everything in the code is okay. Now
it's time to put on another pot of coffee and hope
your spouse remembers who you are after you figure out this rather
annoying problem.
Little bugs like this are often the most difficult to locate. By
Murphy's Law, you can absolutely guarantee that this
code will be in the middle of a huge piece of your project, and the
error reports won't directly lead you here.
What's more, you probably won't
notice the impact of the bug until it goes into production and users
are screaming for a fix.
You cannot afford to forget that once you write code, the story is
not over. People will make changes, additions, and errors in your
code. You will have to look through the code and fix everything that
was messed up. To prevent this problem from occurring, do the
following:
package oreilly.hcj.finalstory;
public class FinalParameters {
public double equation2Better(final double inputValue) {
final double K = 1.414;
final double X = 45.0;
double result = (((Math.pow(inputValue, 3.0d) * K) + X) * M);
double powInputValue = 0;
if (result > 360) {
powInputValue = X * Math.sin(result);
} else {
inputValue = K * Math.sin(result); // <= Compiler error
}
result = Math.pow(result, powInputValue);
if (result > 360) {
result = result / inputValue;
}
return result;
}
When you state that the parameter inputValue is
final, the compiler will catch any attempts to
assign another value to that parameter and give you an error message
with the line number and reason for the problem. The benefit of this
little trick (which takes about two seconds to implement) becomes
even more obvious when you consider the hypothetical Java bean shown
in Example 2-10.
Example 2-10. A bean with a bug
public class Person {
private String name = null;
public void setName(String name) throws PropertyVetoException {
String oldName = this.name;
vetoableChangeSupport.fireVetoableChange("name", oldName, name);
name = name;
propertyChangeSupport.firePropertyChange("name", oldName, name);
}
}
On the emphasized line, the programmer forgot to use the prefix
this on the lefthand side of the assignment; the
line should have read:
this.name = name;
Instead, the assignment does absolutely nothing. In a data model with
212 objects and over 1,000 attributes, bugs like this are extremely
difficult to detect. However, if you have a policy to always label
method parameters as final, such an assignment
will cause a compiler error. The final parameter
version is shown here:
public class Person {
private String name = null;
public void setName(final String name) throws PropertyVetoException {
String oldName = this.name;
vetoableChangeSupport.fireVetoableChange("name", oldName, name);
name = name; // <= Compiler error
propertyChangeSupport.firePropertyChange("name", oldName, name);
}
}
When compiling this code, the programmer immediately gets a compiler
error on the (erroneous) assignment line. The programmer looks back
at the code, spots the bug in about two seconds, fixes it, gets
another soda, and continues work without even thinking about how much
trouble he just avoided. The coding standard here saved him hours of
work.
|
No comments:
Post a Comment