Plenty of people will suggest using BigDecimal and if you don't know how to use rounding in your project, that is what you should do.
If you know how to use decimal rounding correctly, use double. Its many orders of magnitude faster, much clear and simpler and thus less error prone IMHO. If you use dollars and cents (or need two decimal places), you can get an accurate result for values up to 70 trillion dollars.
Basically, you won't get round errors if you correct for it using approriate rounding.
BTW: The thought of rounding errors strikes terror into the heart of many developers, but they are not random errors and you can manage them fairly easily.
EDIT: consider this simple example of a rounding error.
double a = 100000000.01;
double b = 100000000.09;
System.out.println(a+b); // prints 2.0000000010000002E8
There are a number of possible rounding strategies. You can either round the result when printing/displaying. e.g.
System.out.printf("%.2f%n", a+b); // prints 200000000.10
or round the result mathematically
double c = a + b;
double r= (double)((long)(c * 100 + 0.5))/100;
System.out.println(r); // prints 2.000000001E8
In my case, I round the result when sending from the server (writing to a socket and a file), but use my own routine to avoid any object creation.
A more general round function is as follows, but if you can use printf or DecimalFormat, can be simpler.
private static long TENS[] = new long[19]; static {
TENS[0] = 1;
for (int i = 1; i < TENS.length; i++) TENS[i] = 10 * TENS[i - 1];
}
public static double round(double v, int precision) {
assert precision >= 0 && precision < TENS.length;
double unscaled = v * TENS[precision];
assert unscaled > Long.MIN_VALUE && unscaled < Long.MAX_VALUE;
long unscaledLong = (long) (unscaled + (v < 0 ? -0.5 : 0.5));
return (double) unscaledLong / TENS[precision];
}
note: you could use BigDecimal to perform the final rounding. esp if you need a specifc round method.