Friday, October 31, 2008

Manage amounts in Java with BigDecimal

What result do you expect from this sum?
double x = 0.009;
double y = 0.001;
double z = x + y;

The correct value is 0.01 but in Java the result is 0.009999999999999998!

This is the reason why the JDK provides the class BigDecimal: use it always for financial calculation!

Anyway you have to pay some attention to 5 simple rules:
1) Don't forget the operations return always the new value, for example don't do this:
amount.add( thisAmount );

because the right way is
amount = amount.add( thisAmount );


2) When you create a new object use the string constructor, that means new BigDecimal("10.50") instead of new BigDecimal(10.50).

3) To compare never use the .equals() method, because it will compare also the scale and not only the mathematical value. Instead, use the .compareTo() and .signum() methods.

4) When dividing BigDecimals, be careful to specify the rounding in the .divide(...) method. Thus, you should always do:
a = b.divide(c, decimals, rounding);


5) Finally the gold rule for everything: read carefully the API Reference!

Wednesday, October 29, 2008

Remove elements in a List safely

As the javadoc for the interface List states, it provides two methods to efficiently remove entries. But when you remove and entry during iteration a ConcurrentModificationException may occur. To avoid this, use the methode remove in the interface Iterator instead of the one in List. But remember, we're talking about interfaces, thefore there is no warranty that the concrete implementation take care of this behaviour.
Anyway with ArrayList you can use Iterator.remove() without problem. See the example
@Before
public void setup() throws Exception {
list = new ArrayList();
int len = 100;
for (int i = 0; i < len; i++) {
list.add(i);
}
}

@Test(expected = ConcurrentModificationException.class)
public void removeWrong() throws Exception {
for (Iterator iterator = list.iterator(); iterator.hasNext();) {
Integer i = iterator.next();
if (i >= 50) {
// wrong can throw ConcurrentModificationException
list.remove(i);
}
}
}

@Test
public void removeRight() throws Exception {
Assert.assertEquals(100, list.size());
for (Iterator iterator = list.iterator(); iterator.hasNext();) {
Integer i = iterator.next();
if (i >= 50) {
iterator.remove();
}
}
Assert.assertEquals(50, list.size());
}

Also if you synchronize the list with List list = Collections.synchronizedList(new ArrayList(...));, it will throw a ConcurrentModificationException.

Subant: Calls a given target in another build file

There is a very useful ant task, the subant task. It allows to call a target in an external build file.
It requires this syntax:
<subant buildfile="../subproject/build.xml"
target="mytarget"
buildpath="../subproject" />
The best way to use this task, is to invoke it in another target in the current build file.