Skip to content
Lesson 2 of 15

Step 1 of 7 · Reading · ~4 min

Learn

Getting Started

Variables and Types

Java is statically typed: every variable has a type fixed when it is declared, and the compiler checks every use before the program runs. By the end of this lesson you can pick the right numeric type, predict what happens when a value does not fit, and convert between types on purpose.

Declaring a variable

int count = 5;
String city = "Oslo";
count = count + 1;     // fine: same type
count = "six";         // compile error: String cannot be converted to int

A declaration is type name = value;. After that the name only ever holds values of that type. Python lets count become a string later; Java refuses at compile time, which is the point.

The primitive types

TypeSizeHolds
byte8 bits-128 to 127
short16 bits-32,768 to 32,767
int32 bitsabout -2.1 billion to 2.1 billion
long64 bitsabout +/- 9.2 quintillion (literals end in L)
float / double32 / 64 bitsdecimals (double is the default choice)
char16 bitsone character, in single quotes: 'A'
boolean1 valuetrue or false

String is not on this list. It is a class, an object with methods, and uses double quotes. Single quotes are for one char only.

Overflow: the silent trap

Integer types have a fixed range, and arithmetic that leaves it does not fail. It wraps around:

int top = Integer.MAX_VALUE;     // 2147483647
System.out.println(top + 1);     // -2147483648

No exception, no warning, just a wrong number. The subtler version is declaring a long and assuming that makes the math safe:

int w = 100000, h = 100000;
long wrong = w * h;          // 1410065408
long right = (long) w * h;   // 10000000000

In w * h both operands are int, so the multiplication happens in 32 bits and overflows before the result is stored. The long on the left only receives the damaged value. Converting one operand first, (long) w, makes the whole multiplication 64-bit.

Casting: widening and narrowing

Moving to a bigger type is automatic (widening). Moving to a smaller or less precise type must be written with a cast, because data can be lost (narrowing):

double ratio = 7;              // widening, no cast: 7.0
int whole = (int) 3.99;        // narrowing: 3 -- truncated toward zero, not rounded
int neg = (int) -3.99;         // -3
byte small = (byte) 200;       // -56 -- the bits wrap

Mixed arithmetic widens to the larger operand: int + long is a long, int + double is a double. Integer division is its own trap: double d = 7 / 2; stores 3.0, because 7 / 2 is computed as int first.

final and var

final int LIMIT = 100;     // cannot be reassigned
var total = 0L;            // the compiler infers long

final forbids reassignment (for an object it protects the reference, not the contents). var (Java 10+) infers the type from the initializer; the variable is still statically typed, and var works only for local variables that have an initializer.

Wrapper types

Each primitive has an object twin: Integer, Long, Double, Boolean, Character. Collections and generics only hold objects, so ArrayList<Integer> uses the wrapper and Java converts automatically (autoboxing). A wrapper can be null, and unboxing a null into an int throws NullPointerException.

Common mistakes

  • Trusting long x = a * b; when a and b are int. Cast one operand before the operation.
  • Forgetting L: long big = 3000000000; is an error because the literal is read as an int first.
  • Expecting (int) to round. It truncates: (int) 2.99 is 2.
  • Using a local variable before assigning it. Locals have no default value.

Your exercise

Read two integers and print their sum. The twist is the range: each value fits in an int, but the sum may not, and the output must be the true mathematical sum. Decide where the conversion has to happen before the addition.

Up nextNumbers and MathGetting Started

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…