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 oracle.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—he 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 oracle.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.

      
Comments