The Eight Primitive Types
Java has eight primitive types. Each one stores a different kind of basic value. The "when to use" column answers the most common question: "Which int should I use?"
| Type | Size (bytes) | Range (approx.) | When to Use |
|---|---|---|---|
byte
|
1 | -128 to 127 | File I/O streams, network protocol fields, binary data, large byte arrays |
short
|
2 | -32,768 to 32,767 | File format fields, network protocol fields, memory-constrained environments (embedded systems) |
int
|
4 | -2,147,483,647 | Counting, indexing, general-purpose integers — the default integer type |
long
|
8 | -9,223,372,036,854,775 | Large counters, timestamps, database IDs, anything that might exceed 2 billion |
float
|
4 | -3.4 × 10^38 | Graphics rendering (rarely used in business apps), memory-constrained environments, scientific computing |
double
|
8 | -1.7 × 10^308 | Prices, measurements, calculations requiring decimal precision — the default decimal type |
char
|
2 | 0 to 65,535 | Single characters, simple status codes, character-level processing |
boolean
|
1 | 0 or 1 (true/false) | Flags and conditions — the only binary type |
Don't Overthink the int Choice
If you're unsure whether to use
int
or
long
, use
int
. It's the default, and switching to
long
prematurely adds complexity with no benefit unless you actually need numbers larger than 2 billion. You can always switch to
long
later — the assignment is a one-line change.
Declaring and Initializing Variables
Java requires you to declare the type before the name. This is the one syntax rule you must follow:
int score;
int score = 0;
int id = 1;
String name = "Widget Pro";
double price = 19.99;
int quantity;
quantity = 5;
int id = 1;
String name = "Widget Pro";
double price = 19.99;
int quantity = 5;
int id = 1, name = "Widget Pro", price = 19.99, quantity = 5;
Notice the pattern:
type name = value
. The semicolon is required. The type comes first, then the name, then the value. You can declare multiple variables on one line as long as they share the same type.
Variables that are not initialized contain a default value. Using an uninitialized
int score;
gives it the default value of
0
.
Type Casting
Java is a statically typed language. Every variable has a type, and the compiler checks that the value you assign matches. When it doesn't match, you get a compile-time error. Type casting is how you tell the compiler "trust me, I know what I'm doing."
Why You Need to Cast
The most common reason is reading a number from a text source (user input, configuration file, API response). Text is a
String
, numbers are
String
, and they're incompatible. Casting converts between them:
// This line causes a compile error:
String userInput = "42.5";
double price = Double.parseDouble(inputInput); // OK
// This also causes a compile error:
String userInput = "42.5";
int count = (int) userInput); // ERROR
The Narrowing Trap
Casting from a larger type to a smaller type can lose data. Java requires an explicit cast to confirm you accept the risk:
int bigNumber = 200;
byte smallNumber = bigNumber; // ERROR: possible lossy conversion
byte smallNumber = (byte) bigNumber; // OK — explicit cast
Use parseLong() for Large Numbers
Integer.parseInt()
only handles values that fit in an
int
range (-2,147,483,647 to 2,147,483,647). For anything larger, use
Long.parseLong()
. This comes up constantly when reading IDs, timestamps, and file sizes from databases.
The String Type
String is the one type that breaks the "all types are primitive" rule. It's actually a class (a reference type), not a primitive. But Java gives it special syntax to keep it simple to write:
String name = "Hello"; // This creates a String object
Strings are immutable — once created, the value cannot be changed. You can't do
name = name.replace("Hello", "Hi")
. This makes Strings safe to use as map keys and return values from methods (you can't accidentally modify them). The immutability guarantee is why
==
doesn't work for String comparison — two different String objects that contain the same text are still different objects in memory.
// WRONG — compares object identity (are these the same object?)
String a = "Hello";
String b = "Hello";
System.out.println(a == b); // false — they're different objects
// CORRECT — compares the actual content
String a = "Hello";
String b = "Hello";
System.out.println(a.equals(b)); // true
Don't Use + for String Concatenation in Loops
Each
+
in a loop creates a new String object, which is wasteful. In the logging tutorial, we showed
logger.log(Level.INFO, "Order {0} placed by {1}", orderId)
with parameterized logging to avoid this problem. For a standalone script, this rarely matters, but in a server handling thousands of log messages per second, it matters a lot.
Variable Scope and the
final
Keyword
Scope determines where a variable is visible. A variable declared inside a block ({...}) is invisible outside it. A variable declared as a field in a class is visible to all methods in the class. Understanding scope prevents accidental name collisions — two different variables with the same name in different scopes don't interfere with each other.
The Scope Bug: Variable Shadowing
public class ScoreTracker {
private int totalScore = 0;
public void addScore(int points) {
int total = totalScore + points; // BUG: creates a LOCAL variable
}
public int getTotalScore() {
return totalScore; // Still 0 — the local variable
}
}
This bug happens because
int totalScore = totalScore + points
declares a
new local variable
that hides the field. The assignment targets the local variable, not the field. Fix it by renaming one of them.
The
final
Keyword
final
means the variable can only be assigned once. It's most commonly used for
constants
— values that should never change during the program's lifetime:
public static final double TAX_RATE = 0.08;
public class static final double TAX_RATE = 0.08;
public static final String DEFAULT_TAX_RATE = "default";
Don't Use final for Everything
final
is for values that truly never change — configuration values, fixed conversion rates, mathematical constants. Don't use it "just in case" — if a value
might
change, don't make it final. Premature finality makes code harder to modify later.
Summary
- Variables are named storage locations for values in memory, identified by a type. Java requires the type to be declared before the name.
-
Java has eight primitive types:
byte,short,int,long,float,double,char,boolean. Useintby default — it's the default integer type. -
Type casting
converts between types when they don't match. Use
(Type) valuesyntax. Be especially careful with the narrowing trap (large type to smaller type loses data).
String
is a class (a reference type), not a primitive. Use
.equals()
for comparison, not
==
. It's immutable — you can't modify a String object after creation.
final
marks a variable as constant. Use it for values that should never change. Don't use it "just in case."
Where to Go After Variables
Java Methods
Methods organize code into reusable, named blocks. Variables are the data that methods operate on. The Methods tutorial shows you how to define parameters, return values, and call methods.
Classes and Objects
Classes define the structure — fields and methods as a single unit. Variables are the data inside classes. The Classes tutorial shows you how to design them well.
Exception Handling
When things go wrong, exceptions prevent crashes and give you control over the error handling. The Exception Handling tutorial shows you try/catch/finally, custom exceptions, and try-with-resources.