Streams

Mariexshhx

Bekanntes Mitglied
Java:
public class EintragSammler {

  final List<Eintrag> eintraege = new ArrayList<>();
  private String tempZeitstempel;

  public void reduce(String s) {
    if (tempZeitstempel == null) {
      // erste Zeile eines Eintrags aus der Textdatei verarbeiten
    }
    else {
      // zweite Zeile eines Eintrags aus der Textdatei verarbeiten
      tempZeitstempel = null;
    }
  }

  public void join(EintragSammler that) {
    this.eintraege.addAll(that.eintraege);
  }
Java:
public class Odyssee {


  private List<Eintrag> parseEintragListe(Stream<String> lines) {
    // Hier kommt der Code zur Erzeugung der Einträge aus dem Zeilen-Stream rein
    // Verwenden Sie collect in Kombination mit einem EintragSammler-Objekt

    return Collections.emptyList();
  }


  public static void main(String[] args) {
    Odyssee odyssee = new Odyssee();
    List<Eintrag> eintraege = odyssee.readFromInputfile("odyssey.txt");

    // Hier rufen Sie die Methoden zur Analsye der Daten auf

  }


  // Das kann so bleiben
  private List<Eintrag> readFromInputfile(String name) {
    Path inputfile = Path.of(name);
    try (Stream<String> lines = Files.lines(inputfile)) {
      return parseEintragListe(lines);
    } catch (IOException e) {
      throw new RuntimeException("Could not read file: " + name);
    }
  }


}

Kann mir jemand sagen wie man reduce in EintragsSammler implementieren soll? Also wie wird Tempzeitstempel gesetzt ? Einfach mit this.Temzeitstempel = Zeitstempel? Ein Eintrag besteht immer aus einem Zeitstempel und einer Antwortzeit und in den Zeilen der Datei steht immer abwechseln Zeitstempel und Antowortzeit.

Code:
public record Eintrag(LocalDateTime time, int answertime) {

  public Eintrag(String time, String answertime) {
    this(parseTime(time), Integer.parseInt(answertime));
  }

In der Klasse Eintrag werden die beiden Werte dann zum Int geparst. Kenne mich leider noch nicht nicht wirklich mit Streams aus. Mit map könnte ich ja nur einen Wert mappen ich brauche ja aber jeweils zwei. Also wie kann ich immer auf 2 Elemente zugreifen?
 
Zuletzt bearbeitet:

KonradN

Super-Moderator
Mitarbeiter
Du hast da einen Denkfehler denke ich mal. Du willst ja auch eine Liste mit einzelnen "Werten". Die sind halt vom Typ Eintrag.

Also brauchst Du eine Methode, die eine Zeile nimmt und Dir einen Eintrag gibt. Diese kannst Du dann aufrufen in Map. Damit wäre die ganze Methode ein einfaches return mit den folgenden Aktionen auf dem Stream:
  • ggf. filtern von leeren Zeilen
  • Map von String -> Eintrag
  • collect in Liste
 

Mariexshhx

Bekanntes Mitglied
Java:
public class EintragSammler {

  final List<Eintrag> eintraege = new ArrayList<>();
  private String tempZeitstempel;

  public void reduce(String s) {
    if (tempZeitstempel == null) {
      // erste Zeile eines Eintrags aus der Textdatei verarbeiten
    }
    else {
      // zweite Zeile eines Eintrags aus der Textdatei verarbeiten
      tempZeitstempel = null;
    }
  }

  public void join(EintragSammler that) {
    this.eintraege.addAll(that.eintraege);
  }
Java:
public class Odyssee {


  private List<Eintrag> parseEintragListe(Stream<String> lines) {
    // Hier kommt der Code zur Erzeugung der Einträge aus dem Zeilen-Stream rein
    // Verwenden Sie collect in Kombination mit einem EintragSammler-Objekt

    return Collections.emptyList();
  }


  public static void main(String[] args) {
    Odyssee odyssee = new Odyssee();
    List<Eintrag> eintraege = odyssee.readFromInputfile("odyssey.txt");

    // Hier rufen Sie die Methoden zur Analsye der Daten auf

  }


  // Das kann so bleiben
  private List<Eintrag> readFromInputfile(String name) {
    Path inputfile = Path.of(name);
    try (Stream<String> lines = Files.lines(inputfile)) {
      return parseEintragListe(lines);
    } catch (IOException e) {
      throw new RuntimeException("Could not read file: " + name);
    }
  }


}

Kann mir jemand sagen wie man reduce in EintragsSammler implementieren soll? Also wie wird Tempzeitstempel gesetzt ? Einfach mit this.Temzeitstempel = Zeitstempel? Ein Eintrag besteht immer aus einem Zeitstempel und einer Antwortzeit und in den Zeilen der Datei steht immer abwechseln Zeitstempel und Antowortzeit.

Code:
public record Eintrag(LocalDateTime time, int answertime) {

  public Eintrag(String time, String answertime) {
    this(parseTime(time), Integer.parseInt(answertime));
  }

In der Klasse Eintrag werden die beiden Werte dann zum Int geparst. Kenne mich leider noch nicht nicht wirklich mit Streams aus. Mit map könnte ich ja nur einen Wert mappen ich brauche ja aber jeweils zwei. Also wie kann ich immer auf 2 Elemente zugreifen?
 

Mariexshhx

Bekanntes Mitglied
Du hast da einen Denkfehler denke ich mal. Du willst ja auch eine Liste mit einzelnen "Werten". Die sind halt vom Typ Eintrag.

Also brauchst Du eine Methode, die eine Zeile nimmt und Dir einen Eintrag gibt. Diese kannst Du dann aufrufen in Map. Damit wäre die ganze Methode ein einfaches return mit den folgenden Aktionen auf dem Stream:
  • ggf. filtern von leeren Zeilen
  • Map von String -> Eintrag
  • collect in Liste
Die habe ich bereits mit readInputfile die liest die einzelnen Zeilen
 

Mariexshhx

Bekanntes Mitglied
Code:
  public void reduce(String s) {
    if (tempZeitstempel == null) {
      // erste Zeile eines Eintrags aus der Textdatei verarbeiten
      this.tempZeitstempel =s;
    }
    else {
      Eintrag eintrag = new Eintrag(tempZeitstempel,s);
      eintraege.add(eintrag);
      // zweite Zeile eines Eintrags aus der Textdatei verarbeiten
      tempZeitstempel = null;
    }
  }

Also so?
 

KonradN

Super-Moderator
Mitarbeiter
Ach so - da hatte ich nicht gut genug gelesen - die Einträge sind nicht auf einer Zeile sondern immer abwechselnd.

Und ja - das wäre eine Möglichkeit. Dies könnte dann mit Stream.reduce verwendet werden (vermutlich will man in der Aufgabe auf diese Nutzung hinaus).
 

Mariexshhx

Bekanntes Mitglied
Ach so - da hatte ich nicht gut genug gelesen - die Einträge sind nicht auf einer Zeile sondern immer abwechselnd.

Und ja - das wäre eine Möglichkeit. Dies könnte dann mit Stream.reduce verwendet werden (vermutlich will man in der Aufgabe auf diese Nutzung hinaus).
ich verstehe nicht so ganz was ich mit collect machen soll?

Java:
  private List<Eintrag> parseEintragListe(Stream<String> lines) {
    EintragSammler sammler = new EintragSammler();
      lines.forEach(sammler::reduce);
    // Hier kommt der Code zur Erzeugung der Einträge aus dem Zeilen-Stream rein
    // Verwenden Sie collect in Kombination mit einem EintragSammler-Objekt

    return Collections.emptyList();
  }
ich hätte die Einträge jetzt so erzeugt ? Können sie mir helfen? Ich kann doch auch so auf die Liste eines Eintragsammlers Objekt zugreifen?
 

KonradN

Super-Moderator
Mitarbeiter
Also erst einmal würde das, was Du da gemacht hast, auch funktionieren. Das entspricht aber in erster Linie der for each Schleife. Eine for each Schleife einfach nur durch einen Stream zu ersetzen ist eher unüblich und sollte nicht gemacht werden (Josua Bloch hat dazu in Effective Java was geschrieben - ich will es hier jetzt nicht weiter vertiefen.)

Man kann aber auch direkt mittels collect arbeiten. Es gibt mehrere collect Methoden und was wir hier brauchen wäre diese Methode:

Sieht komplizierter aus, als es ist. Was wir hier an Parametern sind folgendes:
  • eine Methode, die eine Instanz zurück gibt vom Sammler. Das wäre dann hier die Erzeugung einer neuen Instanz mit new. Den kann man Referenzieren per EintragSammler::new
  • eine Methode, die ein Element hinzu fügt: das wäre ja die Methode reduce: EintragSammler::reduce wäre also die Methodenreferenz.
  • Zuletzt eine Methode, mit der man zwei Sammler zusammen packen kann. Das ist der Grund für die join Methode: EIntragSammler::join

Dann müssen wir noch schauen, was zurück gegeben wird: Das ist der Sammler. Wir wollen aber nicht den Sammler zurück geben sondern die Liste der Einträge. Also kann man direkt an Code schreiben:
return lines.collect(EintragSammler::new, EintragSammler::reduce, EintragSammler::join).eintraege;

Ja, das ist eine Lösung, die erst einmal so funktioniert. Kann man so zusammen bauen und es wird funktionieren.

Und jetzt kommen meine Bauchschmerzen: Dein EintragSammler hat einen Status. Es spielt also eine große Rolle, in welcher Reihenfolge Einträge gelesen werden. Speziell ist es so, dass immer zwei Einträge zusammen gehören. Das ist so als Streams nicht zu verarbeiten, da es immer zu Problemen kommen kann!

Hintergrund ist, dass Streams auch prinzipiell parallel abgearbeitet werden können. Das ist der Grund, wieso der Sammler das join benötigt. Also angenommen ein Stream mit 3 Einträgen (6 Zeilen) wird parallel abgearbeitet. Was da wir abgearbeitet wird im Multitasking ist immer offen und man müsste sich die Implementierung ansehen. Jetzt kommt nur ein Bildliche Anschauung, die so nicht zwingen passieren können muss:

Eingabe sind 6 Elemente:
E1-a
E1-b
E2-a
E2-b
E3-a
E3-b

Jetzt wird parallel abgearbeitet. Dazu trenne ich die Liste einfach in der Mitte, weil zwei Streams abarbeiten:
Stream 1 verarbeitet also:
E1-a
E1-b
E2-a

Stream 2 verarbeitet also:
E2-b
E3-a
E3-b

Beide bauen aus den ersten zwei Einträgen ein Element, der jeweils 3te EIntrag wird nicht verarbeitet. Somit haben wir an Elementen:
Stream 1: (E1-a, E1-b)
Stream 2: (E2-b, E3-a)
Wir haben bei Stream 2 somit auch falsche Werte ... der b Eintrag ist auf a gelandet! Aber wir nehmen mal an, dass das parsen keine Exception geworfen hat)

Ergebnis aus dem Stream aus 3 Elementen ist damit nur noch:
(E1-a, E1-b), (E2-b, E3-a)

Also bei so eine Lösung habe ich direkt Bauchschmerzen. Ich hoffe, dass ich das verständlich machen konnte. Du hast hier also ein Stream als Eingabe und dieser darf auf keinen Fall ein paralleler Stream sein! Darauf hat Dein Sammler, den Du gebaut hast, aber gar kein Einfluss.
 

Mariexshhx

Bekanntes Mitglied
ich verstehe nicht so ganz wie das bei collect passiert... Ich erzeuge mir ein EintragSammler Objekt und fügen dann in dieses mit meiner reduce Methode die Elemente ein. Wieso habe ich dann am Ende zwei EintragSammler Objekte die ich wieder zusammenfügen muss? Das ist jetzt auf diese Aufgabe bezogen, aber das scheint ja allgemein für collect zu gelten dass man am ende ein "addall" braucht
 

Mariexshhx

Bekanntes Mitglied
Also erst einmal würde das, was Du da gemacht hast, auch funktionieren. Das entspricht aber in erster Linie der for each Schleife. Eine for each Schleife einfach nur durch einen Stream zu ersetzen ist eher unüblich und sollte nicht gemacht werden (Josua Bloch hat dazu in Effective Java was geschrieben - ich will es hier jetzt nicht weiter vertiefen.)

Man kann aber auch direkt mittels collect arbeiten. Es gibt mehrere collect Methoden und was wir hier brauchen wäre diese Methode:

Sieht komplizierter aus, als es ist. Was wir hier an Parametern sind folgendes:
  • eine Methode, die eine Instanz zurück gibt vom Sammler. Das wäre dann hier die Erzeugung einer neuen Instanz mit new. Den kann man Referenzieren per EintragSammler::new
  • eine Methode, die ein Element hinzu fügt: das wäre ja die Methode reduce: EintragSammler::reduce wäre also die Methodenreferenz.
  • Zuletzt eine Methode, mit der man zwei Sammler zusammen packen kann. Das ist der Grund für die join Methode: EIntragSammler::join

Dann müssen wir noch schauen, was zurück gegeben wird: Das ist der Sammler. Wir wollen aber nicht den Sammler zurück geben sondern die Liste der Einträge. Also kann man direkt an Code schreiben:
return lines.collect(EintragSammler::new, EintragSammler::reduce, EintragSammler::join).eintraege;

Ja, das ist eine Lösung, die erst einmal so funktioniert. Kann man so zusammen bauen und es wird funktionieren.

Und jetzt kommen meine Bauchschmerzen: Dein EintragSammler hat einen Status. Es spielt also eine große Rolle, in welcher Reihenfolge Einträge gelesen werden. Speziell ist es so, dass immer zwei Einträge zusammen gehören. Das ist so als Streams nicht zu verarbeiten, da es immer zu Problemen kommen kann!

Hintergrund ist, dass Streams auch prinzipiell parallel abgearbeitet werden können. Das ist der Grund, wieso der Sammler das join benötigt. Also angenommen ein Stream mit 3 Einträgen (6 Zeilen) wird parallel abgearbeitet. Was da wir abgearbeitet wird im Multitasking ist immer offen und man müsste sich die Implementierung ansehen. Jetzt kommt nur ein Bildliche Anschauung, die so nicht zwingen passieren können muss:

Eingabe sind 6 Elemente:
E1-a
E1-b
E2-a
E2-b
E3-a
E3-b

Jetzt wird parallel abgearbeitet. Dazu trenne ich die Liste einfach in der Mitte, weil zwei Streams abarbeiten:
Stream 1 verarbeitet also:
E1-a
E1-b
E2-a

Stream 2 verarbeitet also:
E2-b
E3-a
E3-b

Beide bauen aus den ersten zwei Einträgen ein Element, der jeweils 3te EIntrag wird nicht verarbeitet. Somit haben wir an Elementen:
Stream 1: (E1-a, E1-b)
Stream 2: (E2-b, E3-a)
Wir haben bei Stream 2 somit auch falsche Werte ... der b Eintrag ist auf a gelandet! Aber wir nehmen mal an, dass das parsen keine Exception geworfen hat)

Ergebnis aus dem Stream aus 3 Elementen ist damit nur noch:
(E1-a, E1-b), (E2-b, E3-a)

Also bei so eine Lösung habe ich direkt Bauchschmerzen. Ich hoffe, dass ich das verständlich machen konnte. Du hast hier also ein Stream als Eingabe und dieser darf auf keinen Fall ein paralleler Stream sein! Darauf hat Dein Sammler, den Du gebaut hast, aber gar kein Einfluss.
verstehe was du meinst, ist diese Parallelität immer so? Das wäre ja irgendwie wie bei Threads oder täusche ich mich ?
 

KonradN

Super-Moderator
Mitarbeiter
Streams können oft auch parallel laufen. Ob Stream parallel laufen oder nicht kann man über isParallel abfragen (Bestandteil von BaseStream). Und man kann mittels .parallel() einen parallelen Stream bekommen.

Und ja, das wäre dann eine parallele Ausführung wie bei Threads auch.

ich verstehe nicht so ganz wie das bei collect passiert... Ich erzeuge mir ein EintragSammler Objekt und fügen dann in dieses mit meiner reduce Methode die Elemente ein. Wieso habe ich dann am Ende zwei EintragSammler Objekte die ich wieder zusammenfügen muss? Das ist jetzt auf diese Aufgabe bezogen, aber das scheint ja allgemein für collect zu gelten dass man am ende ein "addall" braucht
Der Stream erstellt zum sammeln der Element ein (oder bei paralleler Verarbeitung eben mehrere) Instanzen zu sammeln. Dazu dient die erste Methodenreferenz.
Jeder einzelne Verarbeiter nutzt dann die Referenz um bei der Instanz des vorherigen Punktes dann Elemente hinzu zu fügen (Mit der zweiten Methodenreferenz, die gegeben wurde).
Wenn der Stream parallel etwas verarbeitet hat, dann gibt es mehrere "Sammler" und diese müssen dann noch zusammen geführt werden. (Mit der dritten Methodenreferenz)

Das wäre dann der kurze Überblick bezüglich der Lösung. Wichtig ist für Dich nur, dass du am Ende genau ein Sammler bekommst wenn collect fertig ist.
 

Mariexshhx

Bekanntes Mitglied
Streams können oft auch parallel laufen. Ob Stream parallel laufen oder nicht kann man über isParallel abfragen (Bestandteil von BaseStream). Und man kann mittels .parallel() einen parallelen Stream bekommen.

Und ja, das wäre dann eine parallele Ausführung wie bei Threads auch.


Der Stream erstellt zum sammeln der Element ein (oder bei paralleler Verarbeitung eben mehrere) Instanzen zu sammeln. Dazu dient die erste Methodenreferenz.
Jeder einzelne Verarbeiter nutzt dann die Referenz um bei der Instanz des vorherigen Punktes dann Elemente hinzu zu fügen (Mit der zweiten Methodenreferenz, die gegeben wurde).
Wenn der Stream parallel etwas verarbeitet hat, dann gibt es mehrere "Sammler" und diese müssen dann noch zusammen geführt werden. (Mit der dritten Methodenreferenz)

Das wäre dann der kurze Überblick bezüglich der Lösung. Wichtig ist für Dich nur, dass du am Ende genau ein Sammler bekommst wenn collect fertig ist.
danke ! Dieser parallele Ablauf wurde in meinem Materialien gar nicht so thematisiert... Quasi ist der letze Schritt zur Sicherheit falls mehrere Streams parallel laufen... Dann könnte ja aber genau dein obenen genannten Problem auftreten... Also wenn ich enen Stream<String> erstelle ist es quasi random, ob dann mehrere Streams parallel laufen oder nur einer ?
 

KonradN

Super-Moderator
Mitarbeiter
danke ! Dieser parallele Ablauf wurde in meinem Materialien gar nicht so thematisiert... Quasi ist der letze Schritt zur Sicherheit falls mehrere Streams parallel laufen... Dann könnte ja aber genau dein obenen genannten Problem auftreten... Also wenn ich enen Stream<String> erstelle ist es quasi random, ob dann mehrere Streams parallel laufen oder nur einer ?
Also Standardmäßig sind Streams alle erst einmal nicht parallel. Daher funktioniert die Lösung so erst einmal.

Die Problematik ist nur, dass eben eine Klasse erzeugt wurde, die gedacht ist um mit Streams zu arbeiten die aber eben bei Parallelen Streams so vermutlich nicht funktionieren wird.

Das kann man ggf. auch etwas besser ausdrücken: Bei Streams ist es immer problematisch, wenn damit Elemente verarbeitet werden, die eine Abhängigkeit zu anderen Elementen haben. Hier ist es die Abhängigkeit zu dem Vorgänger bzw. Nachfolger. Das muss man immer etwas im Kopf behalten. War jetzt evtl. verwirrende Zusatzinformationen aber der Punkt erschien mir wichtig.
 

Mariexshhx

Bekanntes Mitglied
Also Standardmäßig sind Streams alle erst einmal nicht parallel. Daher funktioniert die Lösung so erst einmal.

Die Problematik ist nur, dass eben eine Klasse erzeugt wurde, die gedacht ist um mit Streams zu arbeiten die aber eben bei Parallelen Streams so vermutlich nicht funktionieren wird.

Das kann man ggf. auch etwas besser ausdrücken: Bei Streams ist es immer problematisch, wenn damit Elemente verarbeitet werden, die eine Abhängigkeit zu anderen Elementen haben. Hier ist es die Abhängigkeit zu dem Vorgänger bzw. Nachfolger. Das muss man immer etwas im Kopf behalten. War jetzt evtl. verwirrende Zusatzinformationen aber der Punkt erschien mir wichtig.
ah vielen dank ! Aber wieso wird dann bei dem collect am ende immer ein "addall" verwendet wenn es nur einen Stream gibt oder ist es einfach so gemacht damit es auch für parallele funktioniert ?
 

KonradN

Super-Moderator
Mitarbeiter
Du beziehst Dich auf den Code
return lines.collect(EintragSammler::new, EintragSammler::reduce, EintragSammler::join).eintraege;
richtig?

Das ist ja nur eine Übergabe aller Möglichkeiten. Die Methodenreferenzen werden nur angegeben, da diese benutzt werden könnten (halt bei parallelen Streams).

Ich würde jetzt erwarten, dass bei einem nicht parallelen Stream nie das EintragSammler::join aufgerufen wird. Du kannst da ja eine Ausgabe hinein packen und dann einmal laufen lassen. Dann sieht man ja, ob dies aufgerufen wurde.

Sprich:
Java:
  public void join(EintragSammler that) {
    System.out.println("EintragSammler::join aufgerufen!");
    this.eintraege.addAll(that.eintraege);
  }
Und dann ausführen und schauen, ob es so eine Ausgabe gibt.


Also zum Verständnis: collect braucht dies, damit es immer funktioniert, also auch, wenn der Stream parallel abgearbeitet würde.

Oder habe ich Dich falsch verstanden?
 

Mariexshhx

Bekanntes Mitglied
Du beziehst Dich auf den Code
return lines.collect(EintragSammler::new, EintragSammler::reduce, EintragSammler::join).eintraege;
richtig?

Das ist ja nur eine Übergabe aller Möglichkeiten. Die Methodenreferenzen werden nur angegeben, da diese benutzt werden könnten (halt bei parallelen Streams).

Ich würde jetzt erwarten, dass bei einem nicht parallelen Stream nie das EintragSammler::join aufgerufen wird. Du kannst da ja eine Ausgabe hinein packen und dann einmal laufen lassen. Dann sieht man ja, ob dies aufgerufen wurde.

Sprich:
Java:
  public void join(EintragSammler that) {
    System.out.println("EintragSammler::join aufgerufen!");
    this.eintraege.addAll(that.eintraege);
  }
Und dann ausführen und schauen, ob es so eine Ausgabe gibt.


Also zum Verständnis: collect braucht dies, damit es immer funktioniert, also auch, wenn der Stream parallel abgearbeitet würde.

Oder habe ich Dich falsch verstanden?
ne genau das war meine Frage vielen dank !!

Ich hätte noch eine Frage ich kriege damit ja jetzt eine Liste von Einträgen returnt, was ist wenn ich ich jetzt aus allen einträgen die min/max Antwortzeit haben will? Ich weiß für für streams gibt es max/ min als Funktion, aber ich muss ja erstmal wieder die Antortzeiten aus den Einträgen ziehen brauche ich da nicht eine getAntwortzeit Methode und dann könnte ich auf den Stream erst Filter anwenden und dann max/min?
 

Mariexshhx

Bekanntes Mitglied
Java:
public record Eintrag(LocalDateTime time, int answertime) {

  public Eintrag(String time, String answertime) {
    this(parseTime(time), Integer.parseInt(answertime));
  }

  private static LocalDateTime parseTime(String time) {
    return LocalDateTime.ofInstant(Instant.ofEpochSecond(Long.parseLong(time)), TimeZone
        .getDefault().toZoneId());
  }
}

Die Eintrag Klasse sieht so aus bin mir unsicher, ob man da überhaupt einen Getter braucht ...
 

Mariexshhx

Bekanntes Mitglied
Java:
public record Eintrag(LocalDateTime time, int answertime) {

  public Eintrag(String time, String answertime) {
    this(parseTime(time), Integer.parseInt(answertime));
  }

  private static LocalDateTime parseTime(String time) {
    return LocalDateTime.ofInstant(Instant.ofEpochSecond(Long.parseLong(time)), TimeZone
        .getDefault().toZoneId());
  }
}

Die Eintrag Klasse sieht so aus bin mir unsicher, ob man da überhaupt einen Getter braucht ...
Diese Übergabe wirkt für mich komisch erst wird ein Localdatetime Objekt und ein int übergeben und dann zwei Strings die dann geparset werden...
 

KonradN

Super-Moderator
Mitarbeiter
Diese Übergabe wirkt für mich komisch erst wird ein Localdatetime Objekt und ein int übergeben und dann zwei Strings die dann geparset werden...
Das ist eine Neuheit in Java: Die sogenannten Records. Oder auf Deutsch: Datenklassen.

Eine Einführung findet man z.B. unter https://jax.de/blog/datenklassen-in-java-einfuehrung-in-java-records/

Also um das etwas auseinander zu nehmen:

public record Eintrag(LocalDateTime time, int answertime) { }
Das ist eine Kurzform für eine Klasse, welche:
  • zwei Instanzvariablen hat: time und answertime.
  • einen Konstruktor, der die Instanzvariablen als Parameter annimmt.
  • einen Getter zu jeder Instanzvariable
  • equals, hashcode und toString Implementation

Und dieser Klasse wurde nun noch mehr hinzu gefügt:
  • ein zweiter Konstruktor, der zwei String Parameter entgegen nimmt.
  • eine statische Methode, welche eine Zeit parsen kann

Das wäre dann schon alles.

Und noch zur History:

Dieses Feature von Java ist mit JEP 359 / 384 / 395 entwickelt worden:
Also mit Java 14/15 musste man den Parameter setzten, dass man Preview Funktionen nutzen will, ab Java 16 ist es generell verfügbar.
 

Mariexshhx

Bekanntes Mitglied
Das ist eine Neuheit in Java: Die sogenannten Records. Oder auf Deutsch: Datenklassen.

Eine Einführung findet man z.B. unter https://jax.de/blog/datenklassen-in-java-einfuehrung-in-java-records/

Also um das etwas auseinander zu nehmen:

public record Eintrag(LocalDateTime time, int answertime) { }
Das ist eine Kurzform für eine Klasse, welche:
  • zwei Instanzvariablen hat: time und answertime.
  • einen Konstruktor, der die Instanzvariablen als Parameter annimmt.
  • einen Getter zu jeder Instanzvariable
  • equals, hashcode und toString Implementation

Und dieser Klasse wurde nun noch mehr hinzu gefügt:
  • ein zweiter Konstruktor, der zwei String Parameter entgegen nimmt.
  • eine statische Methode, welche eine Zeit parsen kann

Das wäre dann schon alles.

Und noch zur History:

Dieses Feature von Java ist mit JEP 359 / 384 / 395 entwickelt worden:
Also mit Java 14/15 musste man den Parameter setzten, dass man Preview Funktionen nutzen will, ab Java 16 ist es generell verfügbar.
muss ich mir dann aber nicht um min/max der Antwortzeiten zu bekommen eine getAnswertime Methode schreiben ? und darauf dann die Liste mit den Einträgen mappen? Um dann darauf min/ max aufzurufen ? oder ist keine Get Methode nötig ? kann ich auch anders auf die Antwortzeiten in den Einträgen zugreifen ? vielen dank für deine Erklärung
 

KonradN

Super-Moderator
Mitarbeiter
Ach ja - die Fragestellung hatte ich nicht behandelt.

Erst einmal die aktuelle Frage:
muss ich mir dann aber nicht um min/max der Antwortzeiten zu bekommen eine getAnswertime Methode schreiben ?
Nein, das wäre ja ein Getter und die gibt es ja bereits:
einen Getter zu jeder Instanzvariable
Somit musst Du da nichts weiter machen um darauf zugreifen zu können.

Dann war ein Punkt von Dir, dass Du nun bestimmte Elemente suchen willst. Du hast eine List<Eintrag> und die kannst Du nun immer weiter verwenden. Dazu gibt es die Methode stream(), also wenn Du eine Variable List<Eintrag> eintraege hast, dann bekommst Du einen Stream<Eintrag> per eintraege.stream().
Aber Du willst ja nun ein Minimum bzw Maximum bekommen. Datz gibt es min bzw. max Methoden.
Wenn man sich die Anleitung anschaut, dann sieht man, dass die Methoden einen Comparator haben wollen.

Den Comparator kann man dann natürlich als Lambda Expression schreiben oder man nutzt die Möglichkeiten von Comparator. answerTime ist ein int, also wollen wir int Werte vergleichen. Dazu hat Comparator ein comparingInt. Diese Methode will nun etwas, das einen int liefert. Da kann man dann den Getter als Methodenreferenz angeben. Also sowas wie
.min(Comparator.comparingInt(Eintrag::getAnswerTime))

Damit hast Du ein Optional<Eintrag> mit dem kleinsten Eintrag oder halt ein leeres Optional.
 

Mariexshhx

Bekanntes Mitglied
Ach ja - die Fragestellung hatte ich nicht behandelt.

Erst einmal die aktuelle Frage:

Nein, das wäre ja ein Getter und die gibt es ja bereits:

Somit musst Du da nichts weiter machen um darauf zugreifen zu können.

Dann war ein Punkt von Dir, dass Du nun bestimmte Elemente suchen willst. Du hast eine List<Eintrag> und die kannst Du nun immer weiter verwenden. Dazu gibt es die Methode stream(), also wenn Du eine Variable List<Eintrag> eintraege hast, dann bekommst Du einen Stream<Eintrag> per eintraege.stream().
Aber Du willst ja nun ein Minimum bzw Maximum bekommen. Datz gibt es min bzw. max Methoden.
Wenn man sich die Anleitung anschaut, dann sieht man, dass die Methoden einen Comparator haben wollen.

Den Comparator kann man dann natürlich als Lambda Expression schreiben oder man nutzt die Möglichkeiten von Comparator. answerTime ist ein int, also wollen wir int Werte vergleichen. Dazu hat Comparator ein comparingInt. Diese Methode will nun etwas, das einen int liefert. Da kann man dann den Getter als Methodenreferenz angeben. Also sowas wie
.min(Comparator.comparingInt(Eintrag::getAnswerTime))

Damit hast Du ein Optional<Eintrag> mit dem kleinsten Eintrag oder halt ein leeres Optional.
vielen dank ! Die GetAnswerttime Methode gibt es aber bisher nicht
 

Mariexshhx

Bekanntes Mitglied
Ja, mein Fehler. Die Getter heissen genau so, wie die Namen, die bei record angegeben wurden. Also hier wäre es anwertime.

Optional<Eintrag> maxEintrag = eintraege.stream().max(Comparator.comparingInt(Eintrag::answertime));
achso stimmt die sind durch das record also schon da, hast du ja geschrieben ... record ist neu für mich habe ich vorher noch nie gesehen.. aber wirklich praktisch:) ich danke dir für deine Hilfe !
 

KonradN

Super-Moderator
Mitarbeiter
aber bekomme ich dann nicht einen Optional<Integer> als Rückgabewert ?
Nein, aus dem mapToInt kommt ein IntStream: https://docs.oracle.com/en/java/jav...ml#mapToInt(java.util.function.ToIntFunction)

Die Frage ist, was da dann noch weiter machst. Da kann dann durchaus ein Optional<Integer> bei heraus kommen.
(Optional, weil es denn Fall geben kann, dass es keinen Wert gibt und Integer weil ein Generic nur eine Klasse sein kann und Integer halt der Wrapper zu int ist.)
 

Mariexshhx

Bekanntes Mitglied
Nein, aus dem mapToInt kommt ein IntStream: https://docs.oracle.com/en/java/jav...ml#mapToInt(java.util.function.ToIntFunction)

Die Frage ist, was da dann noch weiter machst. Da kann dann durchaus ein Optional<Integer> bei heraus kommen.
(Optional, weil es denn Fall geben kann, dass es keinen Wert gibt und Integer weil ein Generic nur eine Klasse sein kann und Integer halt der Wrapper zu int ist.)
Optional<Eintrag> maxEintrag = eintraege.stream().max(Comparator.comparingInt(Eintrag::answertime));
wir sollten für die max/ min Antwortzeit eine Methode schreiben die einen int zurückgibt ich hab dann etwas rumgegooglt und bin auf elseorthrow gekommen, dass mir dann einen int zurückgegeben hat. MaptoInt gab dann, wie du schon gesagt hattest keinen int
 

KonradN

Super-Moderator
Mitarbeiter
Also wenn Du nur den Max Wert haben willst, dann kannst Du natürlich auch mit matToInt arbeiten. Dann hast Du den Ablauf:
Stream von Elementen -> Stream von Werten -> größten holen -> Wert aus Optional holen

Ohne mapToInt hast Du
Stream von Elementen -> Element mit größtem Wert holen -> Element aus Optional holen -> Wert des Elements zurück geben.

Mit mapToInt brauchst Du den Comparator nicht anzugeben, denn int ist ja bereits sortierbar.

Es führen immer viele Wege zum Ziel. Die frage ist immer, was man genau will. Was sind die Anforderungen? Hier ist es nur der Wert, der gefordert ist und das kannst du über beide Wege machen.
 

Mariexshhx

Bekanntes Mitglied
Also wenn Du nur den Max Wert haben willst, dann kannst Du natürlich auch mit matToInt arbeiten. Dann hast Du den Ablauf:
Stream von Elementen -> Stream von Werten -> größten holen -> Wert aus Optional holen

Ohne mapToInt hast Du
Stream von Elementen -> Element mit größtem Wert holen -> Element aus Optional holen -> Wert des Elements zurück geben.

Mit mapToInt brauchst Du den Comparator nicht anzugeben, denn int ist ja bereits sortierbar.

Es führen immer viele Wege zum Ziel. Die frage ist immer, was man genau will. Was sind die Anforderungen? Hier ist es nur der Wert, der gefordert ist und das kannst du über beide Wege machen.
wie hole ich den Wert aus den Optional mit get ? oder mit elseorthrow?
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
krgewb Java Streams Java Basics - Anfänger-Themen 10
A Parallel Streams Java Basics - Anfänger-Themen 18
W Streams in Java und was bedeutet meine Konsolen-Ausgabe? Java Basics - Anfänger-Themen 4
M Streams filter Java Basics - Anfänger-Themen 15
M generate Methode für Streams Java Basics - Anfänger-Themen 6
berserkerdq2 Java streams, wann nutze ich ::, also 2x Doppelpuntk bei Streams? Java Basics - Anfänger-Themen 5
B Produkt eines double - streams Java Basics - Anfänger-Themen 3
berserkerdq2 IO Streams logfile erstellen und Sachen schreiben wie? Java Basics - Anfänger-Themen 2
D Verwirrung bei Streams aus primitiven Arrays Java Basics - Anfänger-Themen 2
B Collections Streams - Hilfestellung bei komplexer Struktur Java Basics - Anfänger-Themen 9
S Streams - Abfrage absteigend sortieren Java Basics - Anfänger-Themen 11
S Streams - kleinstes Element finden Java Basics - Anfänger-Themen 4
J String Array zu Map<Character, List<Character>> mit Streams Java Basics - Anfänger-Themen 1
Kirby.exe Fehlende Int Werte aus Array mit streams finden Java Basics - Anfänger-Themen 19
W Eclipse Autoformatierung für Streams ändern ? Java Basics - Anfänger-Themen 1
S Lambda Ausdrücke Streams Java Basics - Anfänger-Themen 6
I Streams Java Basics - Anfänger-Themen 12
N Frage zu Streams Java Basics - Anfänger-Themen 3
U Input/Output Unterschiede Streams Java Basics - Anfänger-Themen 2
X Streams und Ausgabe - lässt sich das einfacher schreiben oder schöner schreiben? Java Basics - Anfänger-Themen 5
C system.out.printf mit streams benutzen Java Basics - Anfänger-Themen 7
C Methoden Sortieren mit Streams: Auf- und absteigend Java Basics - Anfänger-Themen 2
O Streams und die flush Methode Java Basics - Anfänger-Themen 3
P InputStream eines Musik-Streams abspielen Java Basics - Anfänger-Themen 2
M Input/Output Streams Java Basics - Anfänger-Themen 5
T Klassen wie funktionieren Streams, warum bekomme ich int zurück? Java Basics - Anfänger-Themen 2
J Java 8 Streams - Frage zu "reduce" Java Basics - Anfänger-Themen 6
Sogomn Input/Output Reader, Writer und Streams Java Basics - Anfänger-Themen 6
T Fehler mit Streams! Java Basics - Anfänger-Themen 2
T Input/Output Object Streams Java Basics - Anfänger-Themen 6
J Per I/O Streams in LinkedList oder ArrayList schreiben/lesen Java Basics - Anfänger-Themen 6
I Java Streams Java Basics - Anfänger-Themen 6
R Streams for runaways Java Basics - Anfänger-Themen 5
RySa Input/Output Datei kann nicht gelöscht werden, obwohl Streams geschlossen sind. Java Basics - Anfänger-Themen 2
D Input/Output streams und readLine() Java Basics - Anfänger-Themen 3
firefexx Input/Output close() bei mehreren Streams Java Basics - Anfänger-Themen 5
M Frage zu Streams Java Basics - Anfänger-Themen 9
C try finally - Streams schließen Java Basics - Anfänger-Themen 7
M Streams und Sockets Java Basics - Anfänger-Themen 3
M file löschen, streams evtl noch offen Java Basics - Anfänger-Themen 7
G Character-orientierte File-Streams mit der Klasse FileReader Java Basics - Anfänger-Themen 5
S Piped Streams / Threads Java Basics - Anfänger-Themen 6
H Frage zu Byte-Streams Java Basics - Anfänger-Themen 2
P Streams mit Sockets Java Basics - Anfänger-Themen 7
V Performance Lesen und Schreiben aus/in Streams Java Basics - Anfänger-Themen 4
C RandomAccessFile vs. Streams Java Basics - Anfänger-Themen 5
M Probleme mit den Streams Java Basics - Anfänger-Themen 2
G streams schließen Java Basics - Anfänger-Themen 2
P Fragen zu STreams Java Basics - Anfänger-Themen 5
M Streams Java Basics - Anfänger-Themen 4
H Streams etc. erster Versuch Zeilen aus einer Datei zu lesen Java Basics - Anfänger-Themen 6
? Streams Java Basics - Anfänger-Themen 2
R RandomAccessFile mit anderen Streams verbinden Java Basics - Anfänger-Themen 5
G Rekursionsaufgabe mit Streams Java Basics - Anfänger-Themen 5
J Problem mit Streams Java Basics - Anfänger-Themen 15
L Streams und Reader/Writer Java Basics - Anfänger-Themen 8
K Frage zu SdtOut streams bzw. Socket Programmierung Java Basics - Anfänger-Themen 3
M Streams, read and write Java Basics - Anfänger-Themen 2
M Streams Java Basics - Anfänger-Themen 2
B Streams wollen scheinbar nicht schließen Java Basics - Anfänger-Themen 6
S Umwandlung eines Character-Streams in ein Image Java Basics - Anfänger-Themen 17
E Probleme mit Streams Java Basics - Anfänger-Themen 3

Ähnliche Java Themen

Neue Themen


Oben