Java assert: definíciója és célja a kódtesztelés során

21 perc olvasás
A programozó a kód hibáit elemzi, miközben a képernyőn információk jelennek meg.

A szoftverfejlesztés világában minden programozó találkozott már azzal a frusztrációval, amikor a kód látszólag hibátlanul fut, mégis váratlan eredményeket produkál. Éppen ezért olyan eszközökre van szükség, amelyek segítségével már a fejlesztés korai szakaszában felfedezhetjük a logikai hibákat és biztosíthatjuk, hogy programunk a várt módon működjön.

A Java assert mechanizmus egy beépített eszköz, amely lehetővé teszi a programozók számára, hogy feltételeket ellenőrizzenek a kód végrehajtása során. Ez a funkció különböző perspektívákból közelíthető meg: lehet egyszerű hibakereső eszköz, dokumentációs segédlet, vagy akár a tesztelési stratégia szerves része is.

Az alábbi útmutatóból megtudhatod, hogyan használhatod hatékonyan a Java assert kulcsszót a kódod minőségének javítására. Részletes magyarázatot kapsz a működéséről, gyakorlati példákat láthatsz különböző felhasználási területekre, és megismerheted azokat a bevált gyakorlatokat, amelyek segítségével professzionális szinten alkalmazhatod ezt az eszközt.

Az assert alapjai és szintaxisa

Az assert utasítás két fő formában használható Java-ban. Az egyszerűbb változat csak egy logikai kifejezést tartalmaz, míg a bővebb forma egy hibaüzenetet is megadhat.

assert feltétel;
assert feltétel : hibaüzenet;

Az első esetben, ha a feltétel hamis értékre értékelődik ki, akkor AssertionError kivétel keletkezik. A második formánál ugyanez történik, de a kivétel tartalmazza a megadott hibaüzenetet is.

Fontos megjegyzés: "Az assert utasítások alapértelmezés szerint ki vannak kapcsolva a Java futtatókörnyezetben, ezért explicit módon engedélyezni kell őket a -ea vagy -enableassertions kapcsolóval."

Alapvető használati példák

public void setAge(int age) {
    assert age >= 0 : "Az életkor nem lehet negatív: " + age;
    assert age <= 150 : "Az életkor túl nagy: " + age;
    this.age = age;
}

Ez a példa szemlélteti, hogyan ellenőrizhetjük a bemeneti paraméterek helyességét. Az assert segítségével biztosíthatjuk, hogy az életkor értéke ésszerű tartományon belül maradjon.

Engedélyezés és futtatási opciók

Az assert utasítások használatához először engedélyezni kell őket a JVM-ben. Ez többféle módon történhet:

Parancssori kapcsolók

  • -ea vagy -enableassertions: Minden assert engedélyezése
  • -da vagy -disableassertions: Minden assert letiltása
  • -ea:csomagnév: Csak egy adott csomag assert utasításainak engedélyezése
  • -ea:osztálynév: Csak egy adott osztály assert utasításainak engedélyezése
java -ea MyProgram
java -enableassertions:com.example.util MyProgram
java -ea:MyClass -da:com.example.test MyProgram

IDE beállítások

A fejlesztőkörnyezetekben általában a futtatási konfigurációban lehet megadni ezeket a JVM argumentumokat. IntelliJ IDEA-ban a "Run/Debug Configurations" menüpontban, míg Eclipse-ben a "Run Configurations" alatt találjuk ezeket az opciókat.

Kapcsoló Hatás Példa
-ea Globális engedélyezés java -ea MyApp
-ea:com.example Csomag szintű java -ea:com.example MyApp
-da:com.test Csomag szintű tiltás java -da:com.test MyApp
-esa Rendszer assert-ek java -esa MyApp

Gyakorlati alkalmazási területek

Az assert utasítások számos helyzetben hasznosak lehetnek a fejlesztés során. Nézzük meg a legfontosabb alkalmazási területeket részletesen.

Előfeltételek ellenőrzése

Az egyik leggyakoribb használati mód a metódusok bemeneti paramétereinek validálása:

public double calculateSquareRoot(double number) {
    assert number >= 0 : "A négyzetgyök csak nem negatív számokból vonható";
    return Math.sqrt(number);
}

public void processArray(int[] array) {
    assert array != null : "A tömb nem lehet null";
    assert array.length > 0 : "A tömb nem lehet üres";
    
    for (int value : array) {
        assert value >= 0 : "Minden értéknek pozitívnak kell lennie";
        // feldolgozás...
    }
}

Utófeltételek biztosítása

Az assert segítségével ellenőrizhetjük, hogy egy metódus valóban azt az eredményt adja-e vissza, amit elvárunk:

public List<String> filterNonEmptyStrings(List<String> input) {
    List<String> result = input.stream()
        .filter(s -> s != null && !s.isEmpty())
        .collect(Collectors.toList());
    
    assert result.size() <= input.size() : "Az eredmény nem lehet nagyobb az eredetinél";
    assert result.stream().noneMatch(s -> s == null || s.isEmpty()) : 
        "Az eredményben nem lehet null vagy üres string";
    
    return result;
}

Invariánsok fenntartása

Az objektumok belső állapotának konzisztenciáját is ellenőrizhetjük:

public class BankAccount {
    private double balance;
    private boolean isActive;
    
    private void checkInvariant() {
        assert balance >= 0 : "A számlaegyenleg nem lehet negatív";
        assert !isActive || balance >= 0 : "Aktív számla egyenlege nem lehet negatív";
    }
    
    public void deposit(double amount) {
        assert amount > 0 : "A befizetendő összeg pozitív kell legyen";
        
        balance += amount;
        checkInvariant();
    }
    
    public void withdraw(double amount) {
        assert amount > 0 : "A kivenni kívánt összeg pozitív kell legyen";
        assert balance >= amount : "Nincs elegendő fedezet";
        
        balance -= amount;
        checkInvariant();
    }
}

Hibakezelés és kivételek

Amikor egy assert utasítás feltétele hamis értékre értékelődik ki, AssertionError kivétel keletkezik. Ez egy Error típusú kivétel, ami azt jelenti, hogy általában nem javasolt elkapni és kezelni.

AssertionError jellemzői

public void demonstrateAssertionError() {
    try {
        int value = -5;
        assert value > 0 : "Az érték pozitív kell legyen, de " + value;
    } catch (AssertionError e) {
        System.out.println("Assert hiba: " + e.getMessage());
        // Általában nem javasolt az AssertionError elkapása!
    }
}

Fontos megjegyzés: "Az AssertionError elkapása és kezelése ellentmond az assert eredeti céljának, amely a fejlesztési hibák korai felderítése."

Teljesítményhatások

Az assert utasítások teljesítményhatása minimális, különösen akkor, ha ki vannak kapcsolva. Amikor engedélyezve vannak, a feltétel kiértékelése történik meg, ami némi többletterhelést jelenthet.

public void performanceExample(List<Integer> numbers) {
    // Ez drága lehet nagy listáknál, ha az assert engedélyezve van
    assert numbers.stream().allMatch(n -> n > 0) : "Minden számnak pozitívnak kell lennie";
    
    // Jobb megközelítés: egyszerű ellenőrzés
    assert !numbers.isEmpty() : "A lista nem lehet üres";
}

Legjobb gyakorlatok és tervezési minták

Az assert hatékony használatához fontos követni bizonyos irányelveket és bevált gyakorlatokat.

Mit tegyünk és mit ne

Ajánlott használat:

  • Fejlesztési és tesztelési környezetben
  • Belső logika ellenőrzésére
  • Dokumentáció kiegészítésére
  • Komplex algoritmusok helyességének biztosítására

Nem ajánlott használat:

  • Felhasználói bemenet validálására
  • Éles környezetben kritikus üzleti logikára
  • Mellékhatásokkal rendelkező kifejezésekre
// ROSSZ példa - mellékhatás
public void badExample(List<String> items) {
    assert items.remove("test") : "A 'test' elem eltávolítása sikertelen";
    // Ez megváltoztatja a lista tartalmát!
}

// JÓ példa - tiszta ellenőrzés
public void goodExample(List<String> items) {
    assert items.contains("test") : "A 'test' elemnek jelen kell lennie";
    items.remove("test");
}

Dokumentációs érték

Az assert utasítások egyben dokumentációként is szolgálnak, jelezve a kód írójának szándékait:

public int binarySearch(int[] array, int target) {
    assert array != null : "A tömb nem lehet null";
    assert isSorted(array) : "A tömb rendezettnek kell lennie";
    
    int left = 0;
    int right = array.length - 1;
    
    while (left <= right) {
        int mid = left + (right - left) / 2;
        
        if (array[mid] == target) {
            assert mid >= 0 && mid < array.length : "Az index érvényes tartományban van";
            return mid;
        } else if (array[mid] < target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    
    return -1; // Nem található
}

Fontos megjegyzés: "Az assert utasítások segítenek a kód olvashatóságában azáltal, hogy explicit módon kifejezik a programozó feltételezéseit."

Tesztelési stratégiák és integrációk

Az assert mechanizmus jól integrálható különböző tesztelési keretrendszerekkel és fejlesztési folyamatokkal.

Unit tesztelés támogatása

public class Calculator {
    public double divide(double a, double b) {
        assert b != 0 : "Nullával való osztás nem engedélyezett";
        return a / b;
    }
    
    public int factorial(int n) {
        assert n >= 0 : "A faktoriális csak nem negatív egész számokra definiált";
        
        if (n <= 1) return 1;
        
        int result = 1;
        for (int i = 2; i <= n; i++) {
            result *= i;
            assert result > 0 : "Túlcsordulás történt a faktoriális számításban";
        }
        
        return result;
    }
}

Integrációs tesztek

Az assert utasítások integrációs tesztekben is hasznosak lehetnek a rendszer különböző részei közötti kapcsolatok ellenőrzésére:

public class DatabaseService {
    private Connection connection;
    
    public void saveUser(User user) {
        assert connection != null : "Adatbázis kapcsolat nincs inicializálva";
        assert user != null : "A felhasználó objektum nem lehet null";
        assert user.getEmail() != null && !user.getEmail().isEmpty() : 
            "A felhasználónak érvényes email címmel kell rendelkeznie";
        
        // adatbázis művelet...
        
        assert userExists(user.getId()) : "A felhasználó mentése sikertelen";
    }
    
    private boolean userExists(Long userId) {
        // ellenőrző logika
        return true;
    }
}

Continuous Integration környezetben

CI/CD pipeline-okban az assert utasítások automatikusan engedélyezhetők tesztelési fázisban:

# Maven példa
mvn test -Dtest.jvmargs="-ea"

# Gradle példa
gradle test -Dorg.gradle.jvmargs="-ea"
Környezet Assert állapot Indoklás
Fejlesztői Engedélyezett Korai hibafelfedezés
Tesztelési Engedélyezett Regressziók megelőzése
Staging Opcionális Teljesítmény vs. biztonság
Éles Általában letiltott Teljesítmény optimalizálás

Speciális használati esetek

Bizonyos helyzetekben az assert utasítások különösen értékesek lehetnek a kód minőségének javításában.

Komplex adatszerkezetek

public class AVLTree<T extends Comparable<T>> {
    private Node<T> root;
    
    private void checkAVLProperty(Node<T> node) {
        if (node == null) return;
        
        int leftHeight = getHeight(node.left);
        int rightHeight = getHeight(node.right);
        int balanceFactor = leftHeight - rightHeight;
        
        assert Math.abs(balanceFactor) <= 1 : 
            "AVL tulajdonság sérült a csomópontnál: " + node.value;
        
        checkAVLProperty(node.left);
        checkAVLProperty(node.right);
    }
    
    public void insert(T value) {
        assert value != null : "Null érték beszúrása nem engedélyezett";
        
        root = insertRecursive(root, value);
        
        // Invariáns ellenőrzés beszúrás után
        assert isValidAVL() : "Az AVL fa struktúra sérült a beszúrás után";
    }
    
    private boolean isValidAVL() {
        try {
            checkAVLProperty(root);
            return true;
        } catch (AssertionError e) {
            return false;
        }
    }
}

Párhuzamos programozás

Többszálú környezetben az assert segíthet a szinkronizációs problémák felderítésében:

public class ThreadSafeCounter {
    private int count = 0;
    private final Object lock = new Object();
    
    public void increment() {
        synchronized (lock) {
            int oldCount = count;
            count++;
            assert count == oldCount + 1 : "A számláló értéke nem megfelelően növekedett";
        }
    }
    
    public int getValue() {
        synchronized (lock) {
            assert count >= 0 : "A számláló értéke nem lehet negatív";
            return count;
        }
    }
}

Fontos megjegyzés: "Többszálú környezetben az assert utasítások segíthetnek a race condition-ök és egyéb szinkronizációs hibák felderítésében."

Alternatívák és összehasonlítás

Az assert mellett más eszközök is rendelkezésre állnak a kód minőségének biztosítására.

Hagyományos kivételkezelés

// Assert használatával
public void processPositiveNumber(int number) {
    assert number > 0 : "A szám pozitív kell legyen";
    // feldolgozás...
}

// Hagyományos kivételkezeléssel
public void processPositiveNumber(int number) {
    if (number <= 0) {
        throw new IllegalArgumentException("A szám pozitív kell legyen");
    }
    // feldolgozás...
}

Külső validációs könyvtárak

// Google Guava Preconditions
import static com.google.common.base.Preconditions.*;

public void processData(String data, int size) {
    checkNotNull(data, "Az adat nem lehet null");
    checkArgument(size > 0, "A méret pozitív kell legyen");
    checkState(isInitialized(), "Az objektum nincs inicializálva");
}

// Apache Commons Validate
import org.apache.commons.lang3.Validate;

public void processData(String data, int size) {
    Validate.notNull(data, "Az adat nem lehet null");
    Validate.isTrue(size > 0, "A méret pozitív kell legyen");
}

JUnit assert-ek tesztelésben

@Test
public void testCalculation() {
    Calculator calc = new Calculator();
    
    // JUnit assert-ek
    assertEquals(4, calc.add(2, 2));
    assertTrue(calc.isPositive(5));
    assertThrows(IllegalArgumentException.class, () -> calc.divide(1, 0));
    
    // Java assert teszten belül
    int result = calc.multiply(3, 4);
    assert result == 12 : "Szorzás eredménye hibás";
}

Teljesítmény és optimalizáció

Az assert utasítások teljesítményhatásának megértése fontos a hatékony használathoz.

Futásidejű költségek

Amikor az assert utasítások engedélyezve vannak, minden assert kiértékelődik futás közben. Ez különösen fontos ciklusokban vagy gyakran hívott metódusokban:

public void processLargeDataset(List<Integer> data) {
    // Ez drága lehet nagy adathalmazoknál
    assert data.stream().allMatch(n -> n != null) : "Nem lehet null érték";
    
    for (Integer item : data) {
        // Ez minden iterációnál lefut
        assert item > 0 : "Minden elemnek pozitívnak kell lennie";
        processItem(item);
    }
}

// Optimalizált verzió
public void processLargeDatasetOptimized(List<Integer> data) {
    // Egyszer ellenőrizzük az egész listát
    assert data != null && !data.isEmpty() : "Az adatlista nem lehet null vagy üres";
    assert data.stream().allMatch(n -> n != null && n > 0) : 
        "Minden elemnek pozitív egész számnak kell lennie";
    
    for (Integer item : data) {
        processItem(item);
    }
}

Feltételes assert használat

Komplex ellenőrzések esetén érdemes lehet feltételes assert használata:

public class ComplexCalculation {
    private static final boolean DETAILED_ASSERTIONS = 
        Boolean.getBoolean("detailed.assertions");
    
    public double complexOperation(double[] values) {
        assert values != null && values.length > 0 : "Érvényes bemeneti tömb szükséges";
        
        if (DETAILED_ASSERTIONS) {
            assert Arrays.stream(values).allMatch(v -> !Double.isNaN(v)) : 
                "Nem lehet NaN érték a tömbben";
            assert Arrays.stream(values).allMatch(v -> !Double.isInfinite(v)) : 
                "Nem lehet végtelen érték a tömbben";
        }
        
        double result = performCalculation(values);
        
        assert !Double.isNaN(result) : "Az eredmény nem lehet NaN";
        return result;
    }
}

Fontos megjegyzés: "A teljesítmény-kritikus alkalmazásokban érdemes mérni az assert utasítások hatását és szükség szerint optimalizálni."

Hibakeresés és diagnosztika

Az assert utasítások kiváló eszközök a hibakereséshez és a problémák diagnosztizálásához.

Részletes hibaüzenetek

public class MatrixCalculator {
    public double[][] multiply(double[][] a, double[][] b) {
        assert a != null && b != null : "A mátrixok nem lehetnek null értékűek";
        assert a.length > 0 && b.length > 0 : "A mátrixok nem lehetnek üresek";
        assert a[0].length == b.length : 
            String.format("Mátrix dimenzió hiba: %d x %d és %d x %d mátrixok nem szorozhatók", 
                         a.length, a[0].length, b.length, b[0].length);
        
        double[][] result = new double[a.length][b[0].length];
        
        // szorzás implementáció...
        
        assert result.length == a.length : "Eredmény mátrix sor száma hibás";
        assert result[0].length == b[0].length : "Eredmény mátrix oszlop száma hibás";
        
        return result;
    }
}

Logging integráció

import java.util.logging.Logger;
import java.util.logging.Level;

public class ServiceWithLogging {
    private static final Logger logger = Logger.getLogger(ServiceWithLogging.class.getName());
    
    public void processRequest(Request request) {
        boolean assertionsEnabled = false;
        assert assertionsEnabled = true; // Trükk az assert állapot ellenőrzésére
        
        if (assertionsEnabled) {
            logger.log(Level.FINE, "Assert-ek engedélyezve vannak");
        }
        
        assert request != null : logAndAssert("Request nem lehet null");
        assert request.isValid() : logAndAssert("Request validáció sikertelen: " + request);
        
        // feldolgozás...
    }
    
    private String logAndAssert(String message) {
        logger.log(Level.WARNING, "Assert hiba: " + message);
        return message;
    }
}

Debug információk gyűjtése

public class DebuggableService {
    private final Map<String, Object> debugInfo = new HashMap<>();
    
    public Result performOperation(Input input) {
        debugInfo.put("startTime", System.currentTimeMillis());
        debugInfo.put("inputHash", input.hashCode());
        
        assert input != null : "Input nem lehet null. Debug info: " + debugInfo;
        
        Result result = doOperation(input);
        
        debugInfo.put("resultType", result.getClass().getSimpleName());
        debugInfo.put("endTime", System.currentTimeMillis());
        
        assert result != null : "Eredmény nem lehet null. Debug info: " + debugInfo;
        assert isValidResult(result) : 
            "Érvénytelen eredmény. Debug info: " + debugInfo + ", Result: " + result;
        
        return result;
    }
}

Fejlett technikák és minták

Fluent Assert Pattern

public class FluentAssert {
    public static <T> AssertBuilder<T> assertThat(T value) {
        return new AssertBuilder<>(value);
    }
    
    public static class AssertBuilder<T> {
        private final T value;
        
        public AssertBuilder(T value) {
            this.value = value;
        }
        
        public AssertBuilder<T> isNotNull() {
            assert value != null : "Az érték nem lehet null";
            return this;
        }
        
        public AssertBuilder<T> satisfies(Predicate<T> condition, String message) {
            assert condition.test(value) : message;
            return this;
        }
    }
}

// Használat
public void example(String text, List<Integer> numbers) {
    assertThat(text)
        .isNotNull()
        .satisfies(s -> s.length() > 0, "A szöveg nem lehet üres");
    
    assertThat(numbers)
        .isNotNull()
        .satisfies(list -> !list.isEmpty(), "A lista nem lehet üres")
        .satisfies(list -> list.stream().allMatch(n -> n > 0), 
                  "Minden számnak pozitívnak kell lennie");
}

Conditional Assertion Pattern

public class ConditionalAssertions {
    private static final String ASSERTION_LEVEL = 
        System.getProperty("assertion.level", "basic");
    
    public static void basicAssert(boolean condition, String message) {
        if ("none".equals(ASSERTION_LEVEL)) return;
        assert condition : message;
    }
    
    public static void detailedAssert(boolean condition, String message) {
        if (!"detailed".equals(ASSERTION_LEVEL)) return;
        assert condition : message;
    }
    
    public static void performanceAssert(boolean condition, String message) {
        if (!"performance".equals(ASSERTION_LEVEL)) return;
        assert condition : message;
    }
}

Fontos megjegyzés: "A fejlett assert minták segítségével rugalmasabb és karbantarthatóbb kódot írhatunk, miközben megőrizzük az assert eredeti egyszerűségét."

Gyakori hibák és elkerülésük

Mellékhatások az assert-ekben

// ROSSZ - mellékhatás
public void badExample(List<String> items) {
    assert items.removeIf(String::isEmpty) : "Üres stringek eltávolítása sikertelen";
    // Ez megváltoztatja a listát!
}

// JÓ - tiszta ellenőrzés
public void goodExample(List<String> items) {
    assert items.stream().noneMatch(String::isEmpty) : "Nem lehet üres string a listában";
    items.removeIf(String::isEmpty);
}

Túlzott assert használat

// Túlzott assert használat
public int add(int a, int b) {
    assert a != Integer.MAX_VALUE : "Az 'a' paraméter túl nagy";
    assert b != Integer.MAX_VALUE : "A 'b' paraméter túl nagy";
    assert a + b <= Integer.MAX_VALUE : "Túlcsordulás veszélye";
    assert a + b >= Integer.MIN_VALUE : "Alulcsordulás veszélye";
    
    int result = a + b;
    
    assert result == a + b : "Az összeadás eredménye hibás";
    return result;
}

// Megfelelő assert használat
public int addBetter(int a, int b) {
    // Csak a kritikus feltételeket ellenőrizzük
    assert (long)a + b <= Integer.MAX_VALUE && (long)a + b >= Integer.MIN_VALUE : 
        "Túlcsordulás történne: " + a + " + " + b;
    
    return a + b;
}

Assert vs Exception confusion

// Helytelen - felhasználói bemenet ellenőrzése assert-tel
public void processUserInput(String input) {
    assert input != null : "Felhasználói bemenet null"; // ROSSZ!
    // Ha az assert ki van kapcsolva, NullPointerException lesz
}

// Helyes - exception használata
public void processUserInputCorrect(String input) {
    if (input == null) {
        throw new IllegalArgumentException("Felhasználói bemenet nem lehet null");
    }
    
    // Belső logika ellenőrzése assert-tel
    assert isProcessingEnabled() : "Feldolgozás nincs engedélyezve";
}
Mikor használjam az assert kulcsszót Java-ban?

Az assert kulcsszót elsősorban fejlesztési és tesztelési fázisban használd belső logika ellenőrzésére, előfeltételek és utófeltételek biztosítására. Ne használd felhasználói bemenet validálására vagy éles környezetben kritikus üzleti logikára.

Hogyan engedélyezhetem az assert utasításokat?

Az assert utasítások alapértelmezetten ki vannak kapcsolva. Engedélyezéshez használd a -ea vagy -enableassertions JVM kapcsolót. Például: java -ea MyProgram. Specifikus csomagokra: java -ea:com.example MyProgram.

Mi a különbség az assert és a hagyományos kivételkezelés között?

Az assert elsősorban fejlesztési hibák felderítésére szolgál és kikapcsolható éles környezetben. A hagyományos kivételkezelés mindig aktív és felhasználói hibák kezelésére is alkalmas. Az assert AssertionError-t dob, míg a hagyományos validáció Exception leszármazottakat.

Befolyásolja-e az assert a teljesítményt?

Kikapcsolt állapotban az assert utasítások gyakorlatilag nulla teljesítményhatással bírnak. Bekapcsolt állapotban a feltételek kiértékelése történik meg, ami minimális többletterhelést jelenthet. Komplex feltételek esetén érdemes mérni a hatást.

Milyen típusú hibákat lehet elkapni assert segítségével?

Az assert segítségével logikai hibákat, programozói feltételezések megsértését, invariánsok sérülését és algoritmusok helyességi problémáit lehet felderíteni. Különösen hasznos komplex adatszerkezetek és algoritmusok fejlesztésekor.

Használható-e assert többszálú környezetben?

Igen, az assert használható többszálú környezetben, de körültekintően. Segíthet szinkronizációs problémák felderítésében, de nem helyettesíti a megfelelő szálkezelést. Ügyelj arra, hogy az assert feltételek kiértékelése ne okozzon race condition-öket.

Megoszthatod a cikket...
Beostech
Adatvédelmi áttekintés

Ez a weboldal sütiket használ, hogy a lehető legjobb felhasználói élményt nyújthassuk. A cookie-k információit tárolja a böngészőjében, és olyan funkciókat lát el, mint a felismerés, amikor visszatér a weboldalunkra, és segítjük a csapatunkat abban, hogy megértsék, hogy a weboldal mely részei érdekesek és hasznosak.