Kezdő Olvasási idő: ~9 perc

Szintaxis és alap típusok

Primitív típusok, wrapper osztályok, változók, scope, életciklus és típuskonverzió

Szintaxis és alap típusok

A Java nyelv alapkövei: primitív típusok, wrapper osztályok, változók, hatókör, életciklus és típuskonverzió.

1. Definíció

Mi ez?

A Java egy erősen típusos (strongly typed) nyelv, ami azt jelenti, hogy minden változónak deklarálni kell a típusát (vagy a var kulcsszóval ki kell következtetnie a fordítónak). A nyelv alapjait a primitív típusok és az azokat becsomagoló wrapper osztályok adják.

Miért létezik?

  • Típusbiztonság: a fordító compile-time elkapja a típushibákat
  • Teljesítmény: a primitív típusok közvetlenül a stack-en tárolódnak, nem kell heap allokáció
  • Platformfüggetlenség: a típusok mérete rögzített minden platformon (pl. int mindig 32 bit)

Hol helyezkedik el?

Ez a Java nyelv legalapvetőbb szintje — minden más (OOP, Collections, Streams) erre épül.


2. Alapfogalmak

2.1 Primitív típusok

A Java 8 primitív típust tartalmaz:

Típus Méret Alapértelmezett Tartomány Felhasználás
byte 8 bit 0 -128 — 127 Memória-takarékos tömbök, I/O
short 16 bit 0 -32 768 — 32 767 Ritkán használt
int 32 bit 0 -2³¹ — 2³¹-1 Alapértelmezett egész típus
long 64 bit 0L -2⁶³ — 2⁶³-1 Nagy számok, timestamp
float 32 bit 0.0f ~±3.4×10³⁸ Ritkán, inkább double
double 64 bit 0.0d ~±1.7×10³⁰⁸ Alapértelmezett tizedes típus
char 16 bit '\u0000' 0 — 65 535 Unicode karakter
boolean ~1 bit* false true/false Logikai érték

*A boolean mérete implementáció-függő: a JVM általában int-ként (32 bit) tárolja a stack-en.

Fontos szabályok:

  • Primitívek nem lehetnek null
  • Primitívek nem használhatók generics-ben (List<int> ❌, List<Integer> ✅)
  • Az int literálok alapértelmezetten int típusúak, a tizedes literálok double típusúak

2.2 Wrapper osztályok

Minden primitívnek van egy megfelelő wrapper osztálya:

Primitív Wrapper Cache tartomány
byte Byte -128 — 127 (teljes)
short Short -128 — 127
int Integer -128 — 127
long Long -128 — 127
float Float nincs cache
double Double nincs cache
char Character 0 — 127
boolean Boolean TRUE / FALSE (mindkettő)

Autoboxing/Unboxing:

Integer x = 42;        // autoboxing: int → Integer
int y = x;             // unboxing: Integer → int
Integer z = null;
int w = z;             // ⚠️ NullPointerException!

Integer Cache (-128 — 127):

Integer a = 127;
Integer b = 127;
System.out.println(a == b);    // true  (cache-ből jön)

Integer c = 128;
Integer d = 128;
System.out.println(c == d);    // false (új objektumok!)
System.out.println(c.equals(d)); // true  (érték összehasonlítás)

2.3 Változók, scope, lifecycle

Változó típusok:

Típus Deklaráció helye Alapértelmezett Élettartam
Lokális változó Metóduson belül ❌ Nincs (kötelező inicializálni) Blokk vége
Instance változó Osztályban (nem static) ✅ Van Objektum GC-ig
Class változó static ✅ Van Program vége
Paraméter Metódus szignatúra Hívó adja Metódus vége

Scope szabályok:

public void example() {
    int x = 10;            // scope: egész metódus
    if (x > 5) {
        int y = 20;        // scope: csak ez az if blokk
        System.out.println(x + y); // OK
    }
    // System.out.println(y); // ❌ Compile error! y itt nem látható
}

2.4 Type casting

Implicit (widening) — automatikus, veszteségmentes:

byte → short → int → long → float → double
char → int

Explicit (narrowing) — kézi, adatvesztes lehet:

double d = 9.78;
int i = (int) d;    // i = 9 (csonkítás, NEM kerekítés!)

int big = 130;
byte b = (byte) big; // b = -126 (overflow!)

Speciális szabályok:

  • float és double közötti konverzió precíziós veszteséggel járhat
  • intfloat konverziónál is lehet veszteség (float csak 24 bit mantissza)

3. Gyakorlati használat

Mikor mit használj?

Szituáció Ajánlás Miért
Egész számok általában int Alapértelmezett, leggyakoribb
Pénzügyi számítások BigDecimal ⚠️ NEM double! Pontossági hibák!
Kollekcióban szám Integer (wrapper) Generics követelmény
Nagy adathalmaz, memória fontos primitív tömbök Wrapper 16+ byte/elem overhead
Boolean flag boolean primitív Egyszerű, nincs null-kérdés
Nullable boolean (DB-ből) Boolean wrapper null = "nem tudjuk"

Mikor NE használd?

  • double-t pénzügyi kalkulációra0.1 + 0.2 != 0.3
  • ==-t wrapper összehasonlításra — cache határon kívül hibás
  • float-ot, ha nem szükségesdouble a default, float ritka

4. Kód példák

Alap példa — Típusok és konverzió

public class TypeBasics {
    public static void main(String[] args) {
        // Primitívek
        int count = 42;
        double price = 19.99;
        boolean active = true;
        char grade = 'A';

        // Widening (automatikus)
        long bigCount = count;          // int → long, OK
        double bigPrice = count;        // int → double, OK

        // Narrowing (explicit cast szükséges)
        int rounded = (int) price;      // 19 (csonkítás!)
        byte small = (byte) count;      // 42 (belefér)

        // Wrapper autoboxing
        Integer boxed = count;          // autoboxing
        int unboxed = boxed;            // unboxing

        // var (Java 10+) — a típust a fordító következteti ki
        var name = "Alice";             // String
        var number = 42;                // int (NEM Integer!)
        var list = List.of(1, 2, 3);    // List<Integer>
    }
}

Haladó példa — Pénzügyi kalkuláció hibája

public class MoneyPitfall {
    public static void main(String[] args) {
        // ❌ ROSSZ: double pontossági hiba
        double price = 0.1;
        double quantity = 3;
        System.out.println(price * quantity);
        // Output: 0.30000000000000004 (!)

        // ✅ HELYES: BigDecimal használata
        BigDecimal bdPrice = new BigDecimal("0.1");
        BigDecimal bdQuantity = new BigDecimal("3");
        System.out.println(bdPrice.multiply(bdQuantity));
        // Output: 0.3
    }
}

Gyakori csapda — Integer cache

public class IntegerCacheTrap {
    public static void main(String[] args) {
        // Cache-en belül (-128..127): MŰKÖDIK
        Integer a = 100;
        Integer b = 100;
        System.out.println(a == b);      // true ✅

        // Cache-en kívül: NEM MŰKÖDIK
        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-offok

Szempont Primitív Wrapper
Teljesítmény Gyors (stack, nincs allokáció) Lassabb (heap allokáció, GC)
💾 Memória Minimális (pl. int = 4 byte) Jelentős (pl. Integer = ~16 byte)
🔧 Karbantarthatóság Egyszerű, de nem lehet null Null-kezelés kell, de kifejezőbb
🔄 Rugalmasság Nem használható generics-ben Kollekcióban és generics-ben használható

Konkrét számok:

  • int[1000] → ~4 KB memória
  • Integer[1000] → ~20 KB memória (5x több!)
  • Egy millió Integer autoboxing → jelentős GC nyomás

6. Gyakori hibák

1. `==` használata wrapper-eknél

// ❌ Hibás
if (value1 == value2) { ... }  // referencia összehasonlítás!

// ✅ Helyes
if (value1.equals(value2)) { ... }
// vagy
if (Objects.equals(value1, value2)) { ... }  // null-safe

2. `double` használata pénzügyi számításokra

// ❌ Soha ne csinálj ilyet
double balance = 1000.00;
balance -= 999.99;
// balance = 0.010000000000047748 (NEM 0.01!)

// ✅ BigDecimal-t használj
BigDecimal balance = new BigDecimal("1000.00");
balance = balance.subtract(new BigDecimal("999.99"));
// balance = 0.01 ✅

3. Null unboxing

// ❌ NullPointerException dobódik
Integer count = getCountFromDb(); // null-t adhat vissza
int total = count + 1;            // NPE!

// ✅ Null check
int total = (count != null) ? count + 1 : 1;
// vagy Optional használat
int total = Optional.ofNullable(count).orElse(0) + 1;

4. Narrowing cast overflow

// ❌ Csendesen hibás eredmény
int big = 128;
byte b = (byte) big;  // b = -128 (overflow, nincs exception!)

// ✅ Ellenőrzés cast előtt
if (big >= Byte.MIN_VALUE && big <= Byte.MAX_VALUE) {
    byte b = (byte) big;
} else {
    throw new ArithmeticException("Value out of byte range");
}
// vagy Java 8+:
byte b = Math.toIntExact(big); // ArithmeticException overflow-nál

7. Senior szintű meglátások

Mikor számít a primitív vs wrapper választás?

  • Hot path-on (pl. tight loop, valós idejű feldolgozás): mindig primitív. Autoboxing egy milliós ciklusban mérhető lassulást okoz.
  • Domain modellben: wrapper, ha az érték nullable (pl. Integer age — "nem tudjuk az életkorát" vs int age — "0 éves").
  • API tervezésnél: Optional<Integer> jobb, mint nullable Integer.

Integer cache testreszabás

A JVM -XX:AutoBoxCacheMax=<size> flag-gel bővítheti az Integer cache tartományt. Nagyfrekvenciás rendszerekben (pl. ID-k 1-10000 között) ez javíthat a teljesítményen.

`var` használat — mikor igen, mikor ne?

// ✅ Jó: a jobb oldal egyértelművé teszi a típust
var users = new ArrayList<User>();
var response = httpClient.send(request, BodyHandlers.ofString());

// ❌ Rossz: a típus nem egyértelmű
var result = process();          // mi a típusa?
var x = flag ? getA() : getB(); // melyik típus?

JIT optimalizáció

A JIT fordító sok esetben escape analysis segítségével kioptimalizálja az autoboxing-ot, ha a wrapper objektum nem "szökik ki" a metódusból. De erre nem szabad építeni — production kódban mérj!

Floating point összehasonlítás

// ❌ Soha ne használj == -t double-nél
double a = 0.1 + 0.2;
if (a == 0.3) { ... }  // false!

// ✅ Epsilon-alapú összehasonlítás
private static final double EPSILON = 1e-10;
if (Math.abs(a - 0.3) < EPSILON) { ... }  // true

8. Szószedet

Kifejezés Definíció
Autoboxing Primitív típus automatikus konverziója wrapper osztállyá (intInteger)
Unboxing Wrapper osztály automatikus konverziója primitívvé (Integerint)
Widening Implicit típuskonverzió kisebb típusból nagyobba (veszteségmentes)
Narrowing Explicit típuskonverzió nagyobb típusból kisebbe (adatvesztes lehet)
Integer Cache A JVM -128 és 127 közötti Integer objektumokat cache-eli az Integer.valueOf() híváskor
Stack Memóriaterület ahol a lokális primitív változók és referenciák tárolódnak
String Pool → Lásd: String kezelés
Escape Analysis JIT technika: megállapítja, hogy egy objektum "kiszökik-e" a metódusból

9. Gyorsreferencia

  • 🔢 8 primitív típus: byte, short, int, long, float, double, char, boolean
  • 📦 Wrapper = primitív + null + generics kompatibilitás (de drágább)
  • ⚠️ == wrapper-eknél referenciát hasonlít, .equals() kell!
  • 💰 Pénzhez MINDIG BigDecimal, soha double
  • 🎯 Integer cache: -128 — 127 (bővíthető JVM flag-gel)
  • 📏 Widening automatikus, narrowing explicit cast kell
  • 🚫 Null unboxing = NPE — mindig ellenőrizd!
  • 🔍 var (Java 10+) — csak ha a típus egyértelmű a kontextusból
  • Hot path = primitív, domain model = wrapper ha nullable kell
  • 🧮 float ≈ 7 tizedes jegy, double ≈ 15 tizedes jegy precizitás

🎮 Játékok

8 kérdés