uio--WebPageMain-Module

JAVA-B1 Klassen public class instance System.out.println() {@link Klasse} {@param Klasse} getClass().getSimpleName() extends Objekte Interfaces FAQ classes Erweitern von Klassen mit extends finale Konstanten (@see Finalisierung von Klassen ) Polymorphismus Nested Classes @Override Annotation innere Klassen lokale Klassen anonyme Klassen Lamda Expressions FAQ Nested Classes

Klassen im Detail Overview return-Statements return & void return bei primitiven Typen return bei Objekten return-Statements von Methoden mit/ohne return Rückkehr ohne return Rückkehr über return throws Exception Kopie oder Referenz Covariant Return Types this this mit Objekt-Feldern this mit Methoden und im Konstuktor Zugriffsmodifikatoren public protected private Class Member static public static final PI Initialisierung Initialisierung von Feldern Initialisierung von Klassenfeldern Static Block Lambda-Expressions Methoden-Referenzen

Enumerationen und enum-Types Enumerationskonstanten Enumerationen mit Werten Samstag/Sonnabend Example @! Enumerationen FAQ Enum @!Descr/Exmpl/Index

Interfaces Einfache Interfaces (Marker) Interfaces mit Methoden Default-Methoden static Interfaces FAQ Vererbung / Inheritance Vererbung / Inheritance super Keyword method-overriding-and-hiding hiding-of-fields object-as-superclass Finalisierung Finale Klassen und Methoden Finale Methoden Finale Utility-Klasse "IdGenerator" "Template-Methode"-Pattern DataProcessor process(){ r(), p(), w() } Composition-over-Inheritance abstract Abstrakte Klassen und Methoden Beispiel Abstrakte Klassen und Methoden abstract Implementierungsklassen FAQ Vererbung Kein this in super(..) Verhindern Überschreiben von Membern

Generics Generische Programmierung Generische Typparameter Generische Klassen Generische Interfaces Generische Methoden Generische Felder Generische Collection (ArrayList) Diamond Operator Generische Arrays Example Beispiel "GenerischerSpeicher" Ring-Speicher-Algorithus mit generischem Array Beispiel: GenerischePerson mit Berufsgruppe Beispiel: Berufsgruppe mit Static/Non-Static Nested Classes

Modularisierung Package Overview Package Structure Package Info

Modules Overview Setup Setup Module Info

Java New Features Java 8+ Java Record Record Syntax Record Demo Herkömmliche POJOs Lösung mit Records Records Zusammenfassung

INDEX

Records

Records | Overview

Objekte kann man in JAVA nicht nur über Klassen erzeugen sondern auch über Records, es gibt also neben «class A» auch «record A» als Alternative. Records sind für bestimmte Problemstellungen sehr praktisch.

In diesem Themenblock erläutern wir, was Records im Vergleich zu POJOs sind, wozu diese dienen, welche Vorteile Sie haben und wann man diese einsetzen sollte.

Demo

Records | Demo

Der File Demo.java beihaltet das Hauptprogramm zum Testen sowohl der NachrichtClass-Klasse als auch des NachrichtRecord-Records.

Um die Unterschiede zwischen der Verwendung der Klasse und des Records erkennen zu können, muss man schon genauer hinsehen.


 
package com.stuelken.java.b2.records;

import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Consumer;

public class Demo {

	public static void main(String[] args) throws IOException {

		mitKlasse();
		mitRecord();
	}

	public static void mitKlasse() {

		System.out.println("Mit Klasse:");

		Collection<NachrichtClass> nachrichten = new ArrayList<NachrichtClass>();

		NachrichtClass n0, n1, n2;

		LocalDateTime timestamp = LocalDateTime.now();
		n0 = new NachrichtClass(timestamp, "In China ist ein Sack Reis umgefallen.");
		n1 = new NachrichtClass(timestamp, "Kalifornien von Aliens angegriffen.");
		n2 = new NachrichtClass(timestamp, "Bernsteinzimmer bei Hempels gefunden");

		nachrichten.add(n0);
		nachrichten.add(n1);
		nachrichten.add(n2);

		DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
		Consumer<? super NachrichtClass> consumer = nx -> System.out
				.println(nx.getMsgDatum().format(formatter) + ": " + nx.getMsgInhalt());
		nachrichten.forEach(consumer);
	}

	public static void mitRecord() {

		System.out.println("Mit Record:");

		Collection<NachrichtRecord> nachrichten = new ArrayList<NachrichtRecord>();

		NachrichtRecord n0, n1, n2;

		LocalDateTime timestamp = LocalDateTime.now();

		n0 = new NachrichtRecord(timestamp, "In China ist ein Sack Reis umgefallen.");
		n1 = new NachrichtRecord(timestamp, "Kalifornien von Aliens angegriffen.");
		n2 = new NachrichtRecord(timestamp, "Bernsteinzimmer bei Hempels gefunden");

		nachrichten.add(n0);
		nachrichten.add(n1);
		nachrichten.add(n2);

		DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
		Consumer<? super NachrichtRecord> consumer = nx -> System.out
				.println(nx.msgDatum().format(formatter) + ": " + nx.msgInhalt());
		nachrichten.forEach(consumer);

	}

}


 

Erläuterungen

Record braucht keinen Getter

Da die Werte des Record final sind, werden die zugehörigen Getter-Methoden durch Java automatisch erzeugt und tragen den gleichen Namen wie die Komponente msgInhalt() nur eben mit den Klammern des Funktionsoperators.

Vom Prinzip her hätte man die Methode bei der Klasse allerdings genauso bezeichnen können, nur werden Getter bei Klassen in JAVA üblicherweise mit «get» begonnen, wobei wegen camelCase-Syntax dann aber der folgende Buchstabe groß geschrieben wird.

Datum und Zeit, lokal

Ist der einfachste Weg, wie man im Programmcode mal schnell in JAVA einen Zeitstempel bekommen kann.

Um diesen Wert später auch ausgeben zu können, ist ein Formatter erforderlich.

POJO

JAVA-B1 | Herkömmliche POJOs

Um das Verhalten von Records mit herkömmlichen Klassen in etwa realisieren zu können, ist es erforderlich, das Objekt mit Hilfe des Konstruktors erzeugen zu können, dann aber für private Felder auf einen Setter zu verzichten.


 
package com.stuelken.java.b2.records;

import java.time.LocalDateTime;

/**
 * @author t2m
 */
public class NachrichtClass {

	public NachrichtClass(LocalDateTime timestamp, String msgInhalt) {

		if (msgInhalt == null)
			throw new IllegalArgumentException("msgInhalt darf nicht null sein. ");
		if (msgInhalt.length() == 0)
			throw new IllegalArgumentException(
			 "msgInhalt darf kein leerer String sein sondern muss mindestens 1 Zeichen haben.");

		this.msgDatum = timestamp;
		this.msgInhalt = msgInhalt;
	}

	private LocalDateTime msgDatum = null;
	private String msgInhalt = "";

	public LocalDateTime getMsgDatum() {
		return msgDatum;
	}

	public String getMsgInhalt() {
		return msgInhalt;
	}

}

 

Erläuterungen

Private Felder mit Getter ohne Setter

Dadurch, dass die Felder privat sind, kann man von außen auf die zugehörigen Werte nur über den Getter zugreifen. Da der Setter fehlt, kann man den einmal über den Konstruktor gesetzten Wert nicht mehr verändern.

Werte von Argumenten prüfen

Zur Vermeidung fehlerhafter Werte werden wir Exceptions aus. Es ist sinnvoll, hier auf eine IllegalArgumentException auszuweichen.

Records

Records | Lösung mit Records

Bei einem Record wird zumeist nur der Header mit den 1 bis n Komponenten programmiert. Will man aber die Werte noch überprüfen können, ist auch für Records ein Konstrukteur möglich. Dieser hat aber eine andere Syntax als bei Klassen.


 
package com.stuelken.java.b2.records;

import java.time.LocalDateTime;

/**
 * Die zwei Parameter im Header {@link #msgDatum} und {@link #msgInhalt()}
 * bezeichnet man als <b>Komponenten</b> oder englisch Components.
 * 
 * Objekte eines Record sind final und damit unveränderlich.
 * 
 * @author t2m
 */
public record NachrichtRecord(LocalDateTime msgDatum, String msgInhalt) {

	/**
	 * Ein Konstruktor einer {@link Record} benötigt keine Parameter weil die die
	 * Parameter bereits über Record-Header deklariert wurden und als finale
	 * Eigenschaften {@link #msgDatum} und {@link #msgInhalt} vorliegen.
	 * 
	 * @param msgDatum
	 * @param msgInhalt
	 */
	public NachrichtRecord {
		if (msgInhalt == null)
			throw new IllegalArgumentException("msgInhalt darf nicht null sein. ");
		if (msgInhalt.length() == 0)
			throw new IllegalArgumentException(
					"msgInhalt darf kein leerer String sein sondern muss mindestens 1 Zeichen haben.");
	}

}


 

Erläuterungen

Komponenten eines Records

Die zwei Parameter im Header des Record bezeichnet man als Komponenten oder englisch Components. Dieses Record kann also nur erzeugt werden, wenn beide Komponenten vorhanden sind, wobei vom Prinzip auch null übergeben kann.

Konstuktor von Records ohne Parameter

Will man die Werte der Komponenten eines Record überprüfen, kann man auch für Records einen zugehörigen Konstruktor programmieren.

Der Konstruktor eines Record hat aber keine Parameter, weil diese als Komponenten schon im Header angegeben wurden.

Fehler auswerfen - Werte eh nicht änderbar.

Will man die Werte der Komponenten eines Record überprüfen, kann man auch für Records einen zugehörigen Konstruktor programmieren.

Die Werte der Komponenten eines Records verhalten sich finale Member und damit wie Konstanten, können also ohnehin nicht verändert oder korrigiert werden.

Ausgabe

Records | Ausgabe

Die Ausgabe des Programms.


 
Mit Klasse:
20XX-06-14T22:07:39.9325487: In China ist ein Sack Reis umgefallen.
20XX-06-14T22:07:39.9325487: Kalifornien von Aliens angegriffen.
20XX-06-14T22:07:39.9325487: Bernsteinzimmer bei Hempels gefunden
Mit Record:
20XX-06-14T22:07:39.9505383: In China ist ein Sack Reis umgefallen.
20XX-06-14T22:07:39.9505383: Kalifornien von Aliens angegriffen.
20XX-06-14T22:07:39.9505383: Bernsteinzimmer bei Hempels gefunden

 

Zusammenfassung

Records | Zusammenfassung

Immutability/Unveränderlichkeit

Alle Felder eines Record sind final. Sie lassen sich nicht verändern. Mutierende Setter gibt es bei Records nicht.

Bei POJOs sind Felder, wenn man diese zumindest über Argumente im Konstruktor belegen möchte, immer veränderbar. Man kann das Verändern der Werte nur über den Umweg zu finden versuchen, dass die Einschaften private deklariert und für den Zugriff nur eine Getter-Methode schreibt, die Setter-Methode weglässt.

Vererbung: Superklassen

Alle Records erben von java.lang.Record.

POJOs können im Prinzip von allen Klassen erben, sofern die Superklasse eine Vererbung zulässt.

Vererbung: Erweitern

Da Records immer direkt von java.lang.Record erben, kann ein Record B einen anderen Record A nicht mit extends erweitern.

Hinweis: Der Sinn und Zweck besteht hierbei darin, dass Records «strikt wertebasiert» bleiben sollen. Keine tiefe Hierarchie, keine versteckten Instanzfelder, nur finale Felder.

Klassen für POJOs lassen sich immer mit extends erweitern, sofern die Basisklasse nicht mit public final class deklariert wurde.

Interfaces

Auch Records können tatsächlich Interfaces implementieren, und das auch generisch.

interface Message<C> { C content(); }

public record Nachricht<C>(C content) implements Message<C> { }

Eine Record-Komponente content erfüllt die über das Interface vorgegebene abstrakte Methode content() automatisch, ohne dass man zusätzlichen Code programmieren muss.

Man kann auch weitere Methoden über Interfaces vorgeben. Maßgebend ist nur, dass man die Immutability bzw. Immutabilität oder Unveränderlichkeit von Werten bzw. Komponenten des Records einhält.

Records können auch mehrere Interfaces implementieren:

interface Auditable { Instant createdAt(); }

record AuditMessage<C>(C content, Instant createdAt) implements Message<C>, Auditable { }

Klassen für POJOS können durchaus auch generisch sein und ebenso Interfaces implementieren.

Pattern Matching

if (obj instanceof Milk(var date, var days)).. ist ein Beispiel dafür, wie man einen Typenvergleich bei Records durchführen kann.

if (obj instanceof Message<?> m) { System.out.println(m.content()); }

Sealed + Records

Es lassen sich auch versiegelte Records realisieren: So kann man ein sealed Interface definieren, welches über die Angabe von permits aber von UserCreated und OrderPaied verwendet werden kann.

sealed interface IEvent permits UserCreated, OrderPaid { String content() }

record UserCreated(UUID id) implements IEvent { }

record OrderPaid(UUID id, BigDecimal amount) implements IEvent { }

So wird erzwungen, dass beide Records das Interface implementieren dürfen, doch das Record bleibt hierbei weiterhin «final» und damit immutabel bzw. unveränderlich.

Mit Objekts ist das sinngemäß auch möglich.

FootNotes, Keywords, Tags


    Hinweise, Rechte, Marken

    UI ORGANIZED.

    UIO3 Es ist einfacher als Du denkst.

    Stelle noch heute Deine Anfrage.

    uio--WebPageFooter-Module