Monday, December 21, 2009

2.3 Final Parameters











 < Day Day Up > 







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.

















     < Day Day Up > 



    No comments: