Syntax and Basic Types
Primitive types, wrapper classes, variables, scope, lifecycle and type casting
Syntax and Basic Types
The building blocks of Java: primitive types, wrapper classes, variables, scope, lifecycle, and type casting.
1. Definition
What is it?
Java is a strongly typed language, meaning every variable must have its type declared (or inferred by the compiler via var). The language fundamentals are built on primitive types and their corresponding wrapper classes.
Why does it exist?
- Type safety: the compiler catches type errors at compile-time
- Performance: primitive types are stored directly on the stack, no heap allocation needed
- Platform independence: type sizes are fixed across all platforms (e.g.,
intis always 32 bits)
Where does it fit?
This is the most fundamental layer of Java â everything else (OOP, Collections, Streams) builds on top of it.
2. Core Concepts
2.1 Primitive Types
Java has exactly 8 primitive types:
| Type | Size | Default | Range | Usage |
|---|---|---|---|---|
byte |
8 bit | 0 |
-128 to 127 | Memory-efficient arrays, I/O |
short |
16 bit | 0 |
-32,768 to 32,767 | Rarely used |
int |
32 bit | 0 |
-2ÂłÂč to 2ÂłÂč-1 | Default integer type |
long |
64 bit | 0L |
-2â¶Âł to 2â¶Âł-1 | Large numbers, timestamps |
float |
32 bit | 0.0f |
~±3.4Ă10Âłâž | Rarely used, prefer double |
double |
64 bit | 0.0d |
~±1.7Ă10Âłâ°âž | Default decimal type |
char |
16 bit | '\u0000' |
0 to 65,535 | Unicode character |
boolean |
~1 bit* | false |
true/false |
Logical value |
*The
booleansize is implementation-dependent: the JVM typically stores it as anint(32 bits) on the stack.
Key rules:
- Primitives cannot be
null - Primitives cannot be used in generics (
List<int>â,List<Integer>â ) - Integer literals default to
int, decimal literals default todouble
2.2 Wrapper Classes
Every primitive has a corresponding wrapper class:
| Primitive | Wrapper | Cache Range |
|---|---|---|
byte |
Byte |
-128 to 127 (full range) |
short |
Short |
-128 to 127 |
int |
Integer |
-128 to 127 |
long |
Long |
-128 to 127 |
float |
Float |
no cache |
double |
Double |
no cache |
char |
Character |
0 to 127 |
boolean |
Boolean |
TRUE / FALSE (both) |
Autoboxing/Unboxing:
Integer x = 42; // autoboxing: int â Integer
int y = x; // unboxing: Integer â int
Integer z = null;
int w = z; // â ïž NullPointerException!
Integer Cache (-128 to 127):
Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true (from cache)
Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false (new objects!)
System.out.println(c.equals(d)); // true (value comparison)
2.3 Variables, Scope, Lifecycle
Variable types:
| Type | Declared | Default | Lifetime |
|---|---|---|---|
| Local variable | Inside method | â None (must initialize) | End of block |
| Instance variable | In class (non-static) | â Yes | Until object is GC'd |
| Class variable | static |
â Yes | Program termination |
| Parameter | Method signature | Provided by caller | End of method |
Scope rules:
public void example() {
int x = 10; // scope: entire method
if (x > 5) {
int y = 20; // scope: this if block only
System.out.println(x + y); // OK
}
// System.out.println(y); // â Compile error! y not visible here
}
2.4 Type Casting
Implicit (widening) â automatic, lossless:
byte â short â int â long â float â double
char â int
Explicit (narrowing) â manual, may lose data:
double d = 9.78;
int i = (int) d; // i = 9 (truncation, NOT rounding!)
int big = 130;
byte b = (byte) big; // b = -126 (overflow!)
Special rules:
- Conversion between
floatanddoublemay lose precision intâfloatconversion can also lose precision (float has only 24-bit mantissa)
3. Practical Usage
When to use what?
| Situation | Recommendation | Why |
|---|---|---|
| General integers | int |
Default, most common |
| Financial calculations | BigDecimal â ïž |
NOT double! Precision errors! |
| Numbers in collections | Integer (wrapper) |
Generics requirement |
| Large dataset, memory matters | primitive arrays | Wrapper has 16+ bytes/element overhead |
| Boolean flag | boolean primitive |
Simple, no null concerns |
| Nullable boolean (from DB) | Boolean wrapper |
null = "we don't know" |
When NOT to use?
- â
doublefor financial calculations â0.1 + 0.2 != 0.3 - â
==for wrapper comparison â breaks outside cache range - â
floatwhen not necessary âdoubleis the default,floatis rare
4. Code Examples
Basic Example â Types and Conversion
public class TypeBasics {
public static void main(String[] args) {
// Primitives
int count = 42;
double price = 19.99;
boolean active = true;
char grade = 'A';
// Widening (automatic)
long bigCount = count; // int â long, OK
double bigPrice = count; // int â double, OK
// Narrowing (explicit cast required)
int rounded = (int) price; // 19 (truncation!)
byte small = (byte) count; // 42 (fits)
// Wrapper autoboxing
Integer boxed = count; // autoboxing
int unboxed = boxed; // unboxing
// var (Java 10+) â type inferred by compiler
var name = "Alice"; // String
var number = 42; // int (NOT Integer!)
var list = List.of(1, 2, 3); // List<Integer>
}
}
Advanced Example â Financial Calculation Pitfall
public class MoneyPitfall {
public static void main(String[] args) {
// â WRONG: double precision error
double price = 0.1;
double quantity = 3;
System.out.println(price * quantity);
// Output: 0.30000000000000004 (!)
// â
CORRECT: use BigDecimal
BigDecimal bdPrice = new BigDecimal("0.1");
BigDecimal bdQuantity = new BigDecimal("3");
System.out.println(bdPrice.multiply(bdQuantity));
// Output: 0.3
}
}
Common Pitfall â Integer Cache
public class IntegerCacheTrap {
public static void main(String[] args) {
// Within cache (-128..127): WORKS
Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true â
// Outside cache: DOES NOT WORK
Integer c = 200;
Integer d = 200;
System.out.println(c == d); // false â
System.out.println(c.equals(d)); // true â
// â ïž Null unboxing
Integer nullable = null;
// int value = nullable; // NullPointerException!
}
}
5. Trade-offs
| Aspect | Primitive | Wrapper |
|---|---|---|
| ⥠Performance | Fast (stack, no allocation) | Slower (heap allocation, GC) |
| đŸ Memory | Minimal (e.g., int = 4 bytes) |
Significant (e.g., Integer = ~16 bytes) |
| đ§ Maintainability | Simple but can't be null | Requires null handling but more expressive |
| đ Flexibility | Can't be used in generics | Works with collections and generics |
Concrete numbers:
int[1000]â ~4 KB memoryInteger[1000]â ~20 KB memory (5x more!)- One million
Integerautoboxing operations â significant GC pressure
6. Common Mistakes
1. Using `==` with wrappers
// â Wrong
if (value1 == value2) { ... } // reference comparison!
// â
Correct
if (value1.equals(value2)) { ... }
// or
if (Objects.equals(value1, value2)) { ... } // null-safe
2. Using `double` for financial calculations
// â Never do this
double balance = 1000.00;
balance -= 999.99;
// balance = 0.010000000000047748 (NOT 0.01!)
// â
Use BigDecimal
BigDecimal balance = new BigDecimal("1000.00");
balance = balance.subtract(new BigDecimal("999.99"));
// balance = 0.01 â
3. Null unboxing
// â NullPointerException thrown
Integer count = getCountFromDb(); // may return null
int total = count + 1; // NPE!
// â
Null check
int total = (count != null) ? count + 1 : 1;
// or use Optional
int total = Optional.ofNullable(count).orElse(0) + 1;
4. Narrowing cast overflow
// â Silently produces wrong result
int big = 128;
byte b = (byte) big; // b = -128 (overflow, no exception!)
// â
Check before casting
if (big >= Byte.MIN_VALUE && big <= Byte.MAX_VALUE) {
byte b = (byte) big;
} else {
throw new ArithmeticException("Value out of byte range");
}
// or Java 8+:
byte b = Math.toIntExact(big); // ArithmeticException on overflow
7. Senior-level Insights
When does primitive vs wrapper choice matter?
- Hot path (tight loops, real-time processing): always use primitives. Autoboxing in a million-iteration loop causes measurable slowdown.
- Domain models: use wrapper if the value is nullable (e.g.,
Integer ageâ "we don't know the age" vsint ageâ "age is 0"). - API design:
Optional<Integer>is better than a nullableInteger.
Integer Cache Customization
The JVM's -XX:AutoBoxCacheMax=<size> flag can extend the Integer cache range. In high-frequency systems (e.g., IDs ranging 1â10,000), this can improve performance.
`var` usage â when yes, when no?
// â
Good: right-hand side makes type obvious
var users = new ArrayList<User>();
var response = httpClient.send(request, BodyHandlers.ofString());
// â Bad: type is not obvious
var result = process(); // what type is this?
var x = flag ? getA() : getB(); // which type?
JIT Optimization
The JIT compiler can often eliminate autoboxing via escape analysis when the wrapper object doesn't "escape" the method. But don't rely on this â always measure in production code!
Floating Point Comparison
// â Never use == with double
double a = 0.1 + 0.2;
if (a == 0.3) { ... } // false!
// â
Epsilon-based comparison
private static final double EPSILON = 1e-10;
if (Math.abs(a - 0.3) < EPSILON) { ... } // true
8. Glossary
| Term | Definition |
|---|---|
| Autoboxing | Automatic conversion of a primitive type to its wrapper class (int â Integer) |
| Unboxing | Automatic conversion of a wrapper class to its primitive (Integer â int) |
| Widening | Implicit type conversion from a smaller type to a larger one (lossless) |
| Narrowing | Explicit type conversion from a larger type to a smaller one (may lose data) |
| Integer Cache | The JVM caches Integer objects for values -128 to 127 via Integer.valueOf() |
| Stack | Memory area where local primitive variables and references are stored |
| String Pool | â See: String Handling |
| Escape Analysis | JIT technique: determines if an object "escapes" its method scope |
9. Cheatsheet
- đą 8 primitive types:
byte,short,int,long,float,double,char,boolean - đŠ Wrapper = primitive + null + generics compatibility (but more expensive)
- â ïž
==on wrappers compares references, use.equals()! - đ° For money, ALWAYS use
BigDecimal, neverdouble - đŻ Integer cache: -128 to 127 (extendable via JVM flag)
- đ Widening is automatic, narrowing requires explicit cast
- đ« Null unboxing = NPE â always check for null!
- đ
var(Java 10+) â only when type is obvious from context - ⥠Hot path = primitive, domain model = wrapper if nullable needed
- đ§ź
floatâ 7 decimal digits,doubleâ 15 decimal digits precision
đź Games
8 questions