EMZETT.
Login

Kurz: - Sprechende Namen: berechneGesamtpreis, istGueltig, kundenListe - Kleine Methoden, eine Aufgabe; Klassen mit klarer Verantwortung - Konstanten statt magischer Zahlen: static final int MAX_VERSUCHE = 3.

Teil des Kurses Java

Kapitel 21 von 22 im Kurs Java (Abschnitt „Praxis“). Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

Lesbarkeit

  • Sprechende Namen: berechneGesamtpreis, istGueltig, kundenListe
  • Kleine Methoden, eine Aufgabe; Klassen mit klarer Verantwortung
  • Konstanten statt magischer Zahlen: static final int MAX_VERSUCHE = 3;
  • Früh zurückgeben statt tief zu verschachteln
  • Kommentare erklären das Warum; der Code erklärt das Was

Typische Anfängerfehler

1. Strings mit == vergleichen

public class Fehler1 {
    public static void main(String[] args) {
        String eingabe = new String("ja");
        System.out.println((eingabe == "ja") + " " + eingabe.equals("ja"));
        System.out.println("ja".equals(eingabe));          // sicher gegen null auf der linken Seite
    }
}

Ausgabe:

false true
true

2. NullPointerException

import java.util.*;
 
public class Fehler2 {
    static String name(Map<String, String> m, String k) {
        return m.getOrDefault(k, "unbekannt").toUpperCase();      // kein null mehr
    }
    public static void main(String[] args) {
        Map<String, String> m = Map.of("a", "Anna");
        System.out.println(name(m, "a") + " " + name(m, "b"));
        String s = null;
        System.out.println(Objects.requireNonNullElse(s, "Standard"));
        System.out.println(Optional.ofNullable(s).map(String::length).orElse(0));
    }
}

Ausgabe:

ANNA UNBEKANNT
Standard
0

3. Liste während der Iteration ändern

import java.util.*;
 
public class Fehler3 {
    public static void main(String[] args) {
        List<Integer> l = new ArrayList<>(List.of(1, 2, 3, 4));
        try {
            for (Integer x : l) if (x % 2 == 0) l.remove(x);
        } catch (ConcurrentModificationException e) {
            System.out.println("ConcurrentModificationException");
        }
        l.removeIf(x -> x % 2 == 0);                    // richtig
        System.out.println(l);
    }
}

Ausgabe:

ConcurrentModificationException
[1, 3]

4. Integer-Division und Überlauf

public class Fehler4 {
    public static void main(String[] args) {
        int a = 1, b = 2;
        System.out.println(a / b + " " + (double) a / b + " " + (double) (a / b));
        long ms = 1000 * 60 * 60 * 24 * 30;              // int-Überlauf!
        long richtig = 1000L * 60 * 60 * 24 * 30;
        System.out.println(ms + " " + richtig);
    }
}

Ausgabe:

0 0.5 0.0
-1702967296 2592000000

5. Kommazahlen für Geld

import java.math.*;
 
public class Fehler5 {
    public static void main(String[] args) {
        System.out.println(0.1 + 0.2);
        BigDecimal summe = new BigDecimal("0.10").add(new BigDecimal("0.20"));
        System.out.println(summe + " " + summe.setScale(1, RoundingMode.HALF_UP));
    }
}

Ausgabe:

0.30000000000000004
0.30 0.3

6. Ressourcen nicht schließen

Dateien, Streams und Verbindungen immer mit try-with-resources öffnen.

7. Veränderliche Zustände nach außen geben

import java.util.*;
 
public class Fehler7 {
    static class Kurs {
        private final List<String> teilnehmer = new ArrayList<>();
        void anmelden(String n) { teilnehmer.add(n); }
        List<String> getTeilnehmerUnsicher() { return teilnehmer; }                       // von außen veränderbar
        List<String> getTeilnehmer() { return Collections.unmodifiableList(teilnehmer); } // sicher
    }
    public static void main(String[] args) {
        Kurs k = new Kurs();
        k.anmelden("Mia");
        k.getTeilnehmerUnsicher().add("Eindringling");
        System.out.println(k.getTeilnehmer());
        try { k.getTeilnehmer().add("x"); } catch (UnsupportedOperationException e) { System.out.println("geschützt"); }
    }
}

Ausgabe:

[Mia, Eindringling]
geschützt

Moderne Gewohnheiten (Java 17 bis 21)

Statt …besser
langer Datenklasse mit Getternrecord
if (o instanceof X) { X x = (X) o; ... }if (o instanceof X x)
switch mit breakswitch mit ->
String-Konkatenation mit ZeilenumbrüchenTextblock """
Date, Calendarjava.time
new Thread(...) für viele AufgabenExecutor oder Virtual Threads
null-RückgabenOptional oder leere Collections
Schleifen, die Listen bauenStreams (wenn lesbarer)

Namen und Struktur

  • Klassen: Substantive (Rechnung), Methoden: Verben (berechne), Booleans: Fragen (istLeer)
  • Eine öffentliche Klasse pro Datei; Pakete nach Funktion gliedern
  • Keine Abkürzungen wie kdNr; ausschreiben
  • Abhängigkeiten über Konstruktoren hereingeben, an Interfaces programmieren

Logging statt println

In echten Anwendungen schreibt man Meldungen mit einem Logger (java.util.logging, SLF4J). Er kennt Stufen (DEBUG, INFO, WARN, ERROR), Zeitstempel und Ziele:

import java.util.logging.*;
 
public class Log {
    private static final Logger LOG = Logger.getLogger(Log.class.getName());
    public static void main(String[] args) {
        LOG.setUseParentHandlers(false);
        Handler h = new StreamHandler(System.out, new SimpleFormatter() {
            @Override public String format(LogRecord r) { return r.getLevel() + ": " + r.getMessage() + "\n"; }
        });
        LOG.addHandler(h);
        LOG.info("Anwendung gestartet");
        LOG.warning("Speicher wird knapp");
        h.flush();
    }
}

Ausgabe:

INFO: Anwendung gestartet
WARNING: Speicher wird knapp

Leistung

  • Zuerst richtig, dann schnell; messen statt raten (JMH, Profiler wie VisualVM)
  • Passende Collection wählen (ArrayList vs. LinkedList, HashMap vs. TreeMap)
  • StringBuilder in Schleifen; keine unnötigen Objekte in engen Schleifen
  • Datenbank- und Netzwerkzugriffe sind meist der Flaschenhals, nicht die Schleife

Sicherheit

  • Eingaben prüfen und nie in SQL-Texte einfügen: PreparedStatement mit ?
  • Keine Passwörter im Code oder in Logs
  • Abhängigkeiten aktuell halten (OWASP Dependency-Check)
  • Serialisierung fremder Daten (ObjectInputStream) vermeiden

Merke

  • Strings und Objekte mit .equals() vergleichen; null mit Optional oder Standardwerten entschärfen
  • Listen nicht während der Iteration ändern (removeIf)
  • Geld mit BigDecimal; long-Rechnungen mit L-Literalen
  • Unveränderliche Sichten zurückgeben; moderne Sprachmittel nutzen
  • Logger statt System.out, Eingaben prüfen, Abhängigkeiten pflegen

Übungsaufgabe

Suche in einem eigenen Programm nach == bei Strings, nach Rückgaben veränderlicher Listen und nach null-Rückgaben und verbessere sie.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Tests, Pakete und Projektaufbau

Weiter: Nachschlagen: Spickzettel

Alle Kapitel: Java im Überblick