How to use Java’s BigInteger and BigDecimal classes

Overview

Java numeric classes can sometimes be very confusing, therefore I wanted to share my experience with them, specifically the BigInteger and BigDecimal ones.

Creating the values

Even though BigInteger and BigDecimal have the same goal (to represent infinitely growing numbers) the way the construct their values differs somewhat. Consider the following snippet of Java code:

long aLong = 123456789987654321l;
BigInteger bigInt = new BigInteger(aLong);
BigDecimal bigDec = new BigDecimal(aLong);

Surprisingly, we get a compilation error for the BigInteger constructor. Then how are we supposed to convert our primitive numeric values? In such cases it’s best to check if there are any available static constructors (static methods that return an object of the class). Therefore we can rewrite the erroneous line like so:

BigInteger bigInt = BigInteger.valueOf(aLong);

Another interesting discovery is that you can parse String values to BigInteger with a custom radix without having to resort to black magic:

String aString = "1F4D";
BigInteger bigInt = new BigInteger(aString, /* radix */ 16);

Dealing with aggregates

The old-style of finding the sum or product of a numeric class in Java is very verbose and contains a lot of boilerplate code:

BigInteger result = BigInteger.Zero;
for (BigInteger bigInt : bigIntCollection) {
    result = result.add(bigInt);
}

It is imperative that we not forget the assignment back to the result variable, lest we lose our actual result :o) We can much quickly and safely get the same result by using the Stream API that was introduced in Java 8:

BigInteger result = bigIntCollection.stream()
        .reduce(BigInteger.ZERO, BigInteger::add);

Ain’t that sweet?

Rounding hell

Dividing BigDecimal values is harder than it sounds. Why? Because if the result of the division is not an exact result, which in most cases isn’t, then you’ll get slapped by an exception (in the face). To avoid the lovely ArithmeticException we should always supply a limited MathContext or scale and rounding parameters:

BigDecimal result1 = bigDec1.divide(bigDec2, MathContext.DECIMAL128);
BigDecimal result2 = bigDec1.divide(bigDec2, /* scale */ 9, RoundingMode.HALF_UP);

Additionally we can “re-scale” a value to a more generous or limiting decimal constraint. Some accounting tasks may require this kind of calculation 😉 Like dragon accounting 😀

BigDecimal result = bigDec1.divide(bigDec2, /* scale */ 9, RoundingMode.UP);
BigDecimal scaled = result.scale(/* scale */ 7, RoundigMode.DOWN);

Formatting values

In the end all values must be presented to the user in a friendly way. Outputting values with thousands of digits is an easy way to scare potential customers away. To our rescue comes the DecimalFormat class:

DecimalFormat formatter = new DecimalFormatter("0.####");
formatter.format(new BigDecimal(123456789.87654321);

The downside is, it’s going to use the current locale to output the decimal separator and to override it requires some ugly looking code like:

DecimalFormat formatter = new DecimalFormatter("0.####",
        new DecimalFormatSymbols(Locale.US));

What about if we want to use custom rounding to the values?

formatter.setRoundingMode(RoundingMode.DOWN);

– This is madness!
– Madness? THIS. IS. JAVAAAAAAAAA!!!

A good alternative to all of this verbosity is to use the String.format or MessageFormat APIs. Here’s an example with String.format:

String.format(Locale.US, "%.4f", bigDec.setScale(4, RoundingMode.DOWN));

Happy coding!

How to setup a JavaFX 8 project in IntelliJ

Overview

JavaFX 8 is the newest Java framework for creating rich multi-platform desktop applications that it ships out of the box with the standard edition JRE. The framework has been developed by learning from the mistakes of the previous such libraries (AWT, Swing, and the first JavaFX). The only downside is that it requires Java 8 and above to run.

This post will be about how to setup an IntelliJ IDEA project for a complex application with JavaFX 8 the way it should be done.

Prerequisites

To start the project we should download and install the following programs:

  1. IntelliJ Community or Ultimate edition – download
  2. Java Development Toolkit 8 – download
  3. JavaFX Scene Builder 2.0 – download

Create the project

  1. Start up IntelliJ and start a new project using File > New > Project:
    Project
  2. Name your project as you’d like and it should look similar to this:
    CreatedProject

This is all good for a small app. We get a sample organization of our files but for a large project this structure will not do.

Improve the project

To scale up we need to create well defined packages for our separate class-types. The controllers, models and views. By design JavaFX is MVC (Model-View-Controller) oriented and we should leverage that fact by exploiting the built-in mechanisms for organizing the code.

So before we start with coding we should:

  1. Add our default package name for the sake of the example that would be “com.example.javafxapp”
  2. Create 3 more sub-packages “controller”, “model” and “view”.
  3. Leave the Main file on the top-level
  4. Move the Controller class to the “controller” package
  5. Rename and move the FXML view file to the “view” package

In the end the result should look like this:
ImprovedProject

Setup Scene Builder with IntelliJ

One of the best ways to develop the UI for the JavaFX application is to use the WYSIWYG (What You See Is What You Get) tool named Scene Builder. IntelliJ lets you run it from the context menu of your view files to save time. The first time you need to tell IntelliJ where to look for the installed Scene Builder executable:

Where to go from here

Now that you have the advanced project setup in place you can start using Scene Builder to create your initial user interface and add programmatic behaviour to it via the controller classes. Don’t forget to externalize your application logic to the model classes so that they are unit testable without depending on UI code.

A great article on how to start with Scene Builder (albeit using Eclipse instead of IntelliJ) is posted here, so be sure to check it out as well.

Thank you for reading!