Tax Calculator using Java 8 and BigDecimal I am learning Java8 and BigDecimal. The following exercise involved
writing a Tax Calculator that took a salary and calculated the tax
payable based on the tax band into which the salary falls. The test
passes as the code stands but if I remove the call to 

setScale(0, BigDecimal.ROUND_UP)


then the rounding does not occur and the tests fail like this >

TaxCalculator.calculateTax &gt; 712.50

java.lang.AssertionError:  Expected: is &lt;713&gt;
      but: was &lt;712.50&gt;


I don't understand that because the 2nd parameter to the divide call
specifies that rounding should be performed. 

Also, Can anyone suggest
improvements to the way this class is written please? I'm just trying
to nail down best practices with respect to the Streams API. Am I using
an appropriate way to calculate a percentage in Java?

import org.junit.Before;
import org.junit.Test;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.TreeMap;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

public class TaxCalculatorTest {

    private TaxCalculator taxCalculator;

    private HashMap&lt;BigDecimal, BigDecimal&gt; testData = new HashMap&lt;&gt;(); // &lt;salary, taxPayable&gt;
    private TreeMap&lt;BigDecimal, BigDecimal&gt; taxBands = new TreeMap&lt;&gt;(); // uses natural ordering of keys
    // Could have used LinkedHashMap to maintain order but that relies on entries being inserted in the correct order

    @Before
    public void setup() {

        testData.put(new BigDecimal("5000"), new BigDecimal("225"));
        testData.put(new BigDecimal("11000"), new BigDecimal("413"));
        testData.put(new BigDecimal("19000"), new BigDecimal("713"));
        testData.put(new BigDecimal("27000"), new BigDecimal("905"));

        taxBands.put(new BigDecimal("10000"), new BigDecimal("4.5"));
        taxBands.put(new BigDecimal("35000"), new BigDecimal("3.35"));         // TreeMap fixes the ordering
        taxBands.put(new BigDecimal("20000"), new BigDecimal("3.75")); // This entry will be inserted before the previous one

        taxCalculator = new TaxCalculator(taxBands);
    }

    @Test
    public void calculateTax(){

        testData.forEach((salary, taxPayable) -&gt; {

            assertThat(taxCalculator.calculateTax(salary), is(taxPayable));
        }) ;
    }
}



import java.math.BigDecimal;
import java.util.HashMap;
import java.util.TreeMap;

class TaxCalculator {

    private static final BigDecimal NO_TAX = new BigDecimal("0");


    /*
     * scale &gt; the number of digits to the right of the decimal point
     *
     * precision &gt; the number of significant digits
     *
     * BigDecimal instances are immutable
     *
     */

    private BigDecimal ONE_HUNDRED = new BigDecimal("100");

    private final TreeMap&lt;BigDecimal, BigDecimal&gt; taxBands;

    TaxCalculator(TreeMap&lt;BigDecimal, BigDecimal&gt; taxBands) {
        this.taxBands = taxBands;
    }

    BigDecimal calculateTax(BigDecimal salary) {

        BigDecimal taxPayable = salary.multiply(getTaxRate(salary)).divide(ONE_HUNDRED, BigDecimal.ROUND_UP).setScale(0, BigDecimal.ROUND_UP);

        System.out.println("TaxCalculator.calculateTax &gt; " + taxPayable);
        return taxPayable;
    }


    private BigDecimal getTaxRate(BigDecimal salary) {

        return taxBands.entrySet().stream()
                .filter((entry) -&gt; salary.compareTo(entry.getKey()) &lt; 0)
                .map(HashMap.Entry::getValue)
                .findFirst().orElse(NO_TAX);
    }
}
The rounding doesn't work the way you expect it to work for division. From documentation:


  Returns a BigDecimal whose value is (this / divisor), and whose scale is this.scale().


The product of the salary and the tax rate has two digits after the decimal point. So does the quotient. 
The getTaxRate method is unnecessarily long and complicated. You're trying to find the largest entry in a TreeMap such that is less than the given value. That's exactly what the lower method does. 
Printing something inside the calculateTax method is a bad idea. It makes the code less reusable (what if I want to just calculate the tax without any logging?). And violates the single responsibility principle (it calculates the tax and prints something to standard output).
This kind of comments:

/*
 * scale &gt; the number of digits to the right of the decimal point
 *
 * precision &gt; the number of significant digits
 *
 * BigDecimal instances are immutable
 *
 */


is even worse than useless. It clutters the code with irrelevant information. The documentation for the BigDecimal class belongs to the BigDecimal class, not to a TaxCalculator.

There several other comments in your code that repeat parts of the TreeMap class documentation. They're also gibberish. Removing all these comments will make the code cleaner.
Adding doc comments for your TaxCalculator class and its public is a good idea. They should describe what it represents, what are the pre- and post-conditions of each method (for instance, what happens if I pass a negative salary? In your case, it's garbage in- garbage out. Document that. It's obvious from the method signature itself).
You might want to add proper input validation (for instance, you can throw the exception if the salary is negative). 
You can also use the valueOf static factory method to convert integers to BigDecimal's: to me, BigDecimal.valueOf(100) looks better than new BigDecimal("100"). It can also reuse frequent values.