Primitive Types

Know the eight primitive types, their sizes and literal forms, and which one to pick for counts, IDs, sizes, flags and money.

Syntaxint count = 42; long id = 9_000_000_000L; double ratio = 0.75; float f = 0.75f; char c = 'A'; boolean ok = true; byte b = 0x7F;

Java has eight primitive types. They hold the value directly, they cannot be null, and their sizes are the same on every platform:

TypeSizeRange or use
byte8 bits-128 to 127; raw bytes from files and sockets
short16 bits-32,768 to 32,767; rarely used
int32 bitsabout plus or minus 2.1 billion; the default for whole numbers
long64 bitsabout plus or minus 9.2 quintillion; IDs, timestamps, byte counts
float32 bitsabout 7 significant digits
double64 bitsabout 15 to 16 significant digits; the default for decimals
char16 bitsone UTF-16 code unit, unsigned
booleannot specifiedtrue or false only

Literals

A whole-number literal is an int unless it ends in L, so 5_000_000_000 does not compile but 5_000_000_000L does. A decimal literal is a double unless it ends in f. Underscores between digits are ignored and make large numbers readable. 0x starts hexadecimal and 0b binary.

Choosing a type in back-end code

Use int for counts, sizes of in-memory things and loop indexes. Use long for database IDs (a BIGINT column), epoch milliseconds and file sizes: an int runs out at about 2.1 billion, and tables and files get there. Use boolean for flags, never 0 and 1.

Do not use double or float for money. They are binary fractions, so 0.1 has no exact form and 0.1 + 0.2 is 0.30000000000000004. Store money as a long count of minor units (cents) or use BigDecimal. Compare doubles with a tolerance, not ==. Floating-point division by zero does not throw: it gives Infinity or NaN, and NaN is not equal even to itself.

A char is a number underneath, which is why 'A' + 1 is 66. It holds one UTF-16 code unit, so characters outside the Basic Multilingual Plane, such as most emoji, take two char values. Work with String for text.

One more back-end trap: JSON numbers are often read by JavaScript, which loses precision above 2 to the power 53. Large long IDs are safer sent as strings in public APIs.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Map a BIGINT primary key column to long so IDs keep working past 2.1 billion rows.
  • Store order totals as a long number of cents so sums and refunds stay exact.
  • Compute a cache expiry in epoch milliseconds with long arithmetic so it cannot wrap negative.

More examples

Why doubles are wrong for money

Binary floating point cannot store 0.1 exactly, so equality checks fail. Counting whole cents in a long keeps every sum exact, and you only format at the edge.

Example · java
void main() {
    double sum = 0.1 + 0.2;
    IO.println(sum);
    IO.println(sum == 0.3);
    IO.println(Math.abs(sum - 0.3) < 1e-9);

    long priceCents = 1999;
    long shippingCents = 450;
    long totalCents = priceCents + shippingCents;   // exact
    IO.println(totalCents / 100 + "." + String.format("%02d", totalCents % 100));
}
// Output:
// 0.30000000000000004
// false
// true
// 24.49

char is a number

Arithmetic on char promotes to int, so 'a' + 'b' is 97 + 98. The emoji is one code point but two UTF-16 code units, which is why length() returns 2 and codePointCount returns 1.

Example · java
void main() {
    char c = 'A';
    IO.println(c + 1);              // int arithmetic
    IO.println((char) (c + 1));     // back to a char
    IO.println('a' + 'b');          // two chars add as numbers
    IO.println("" + 'a' + 'b');     // string concatenation
    IO.println(Character.isDigit('7') + " " + Character.getNumericValue('7'));
    String rocket = Character.toString(0x1F680);   // one emoji
    IO.println(rocket.length() + " " + rocket.codePointCount(0, rocket.length()));
}
// Output:
// 66
// B
// 195
// ab
// true 7
// 2 1

int overflow in a time calculation

Thirty days in milliseconds is larger than Integer.MAX_VALUE, so the int product wraps to a negative number without any error. Floating-point division by zero gives Infinity or NaN instead of throwing, so check with Double.isNaN.

Example · java
void main() {
    int wrongMs = 30 * 24 * 60 * 60 * 1000;    // 30 days, computed in int
    long rightMs = 30L * 24 * 60 * 60 * 1000;  // L makes the whole product long
    IO.println(wrongMs);
    IO.println(rightMs);

    IO.println(1.0 / 0);
    IO.println(0.0 / 0);
    double nan = 0.0 / 0;
    IO.println((nan == nan) + " " + Double.isNaN(nan));
}
// Output:
// -1702967296
// 2592000000
// Infinity
// NaN
// false true

Discussion

  • Be the first to comment on this lesson.