Einführung in jOOL

Einführung in JOOL

1. Überblick

In diesem Artikel betrachten wir die BibliothekjOOL __ - ein weiteres Produkt ausjOOQ.

2. Maven-Abhängigkeit

Beginnen wir mit dem Hinzufügen einer Maven-Abhängigkeit zu Ihrenpom.xml:


    org.jooq
    jool
    0.9.12

Sie finden die neueste Versionhere.

3. Funktionale Schnittstellen

In Java 8 sind die funktionalen Schnittstellen sehr begrenzt. Sie akzeptieren die maximale Anzahl von zwei Parametern und verfügen nicht über viele zusätzliche Funktionen.

jOOL behebt dies, indem es eine Reihe neuer Funktionsschnittstellen beweist, die sogar 16 Parameter (vonFunction1 bisFunction16) akzeptieren können und mit zusätzlichen praktischen Methoden angereichert sind.

Um beispielsweise eine Funktion mit drei Argumenten zu erstellen, können wirFunction3: verwenden

Function3 lengthSum
  = (v1, v2, v3) -> v1.length() + v2.length() + v3.length();

In reinem Java müssten Sie es selbst implementieren. Außerdem haben funktionale Schnittstellen von jOOL eine MethodeapplyPartially(), mit der wir eine Teilanwendung einfach durchführen können:

Function2 addTwoNumbers = (v1, v2) -> v1 + v2;
Function1 addToTwo = addTwoNumbers.applyPartially(2);

Integer result = addToTwo.apply(5);

assertEquals(result, (Integer) 7);

Wenn wir eine Methode vom TypFunction2haben, können wir sie mithilfe einertoBiFunction()-Methode einfach in eine Standard-JavaBiFunction umwandeln:

BiFunction biFunc = addTwoNumbers.toBiFunction();

In ähnlicher Weise gibt es einetoFunction()-Methode imFunction1-Typ.

4. Tuples

Ein Tupel ist ein sehr wichtiges Konstrukt in einer funktionalen Programmierwelt. Es ist ein typisierter Container für Werte, bei denen jeder Wert einen anderen Typ haben kann. Tuples are often used as function arguments.

Sie sind auch sehr nützlich, wenn Sie Transformationen für einen Strom von Ereignissen durchführen. In jOOL gibt es Tupel, die von einem bis zu sechzehn Werten umbrochen werden können, bereitgestellt vonTuple1 bisTuple16 Typen:

tuple(2, 2)

Und für vier Werte:

tuple(1,2,3,4);

Betrachten wir ein Beispiel, wenn wir eine Folge von Tupeln haben, die drei Werte enthalten:

Seq> personDetails = Seq.of(
  tuple("michael", "similar", 49),
  tuple("jodie", "variable", 43));
Tuple2 tuple = tuple("winter", "summer");

List> result = personDetails
  .map(t -> t.limit2().concat(tuple)).toList();

assertEquals(
  result,
  Arrays.asList(tuple("michael", "similar", "winter", "summer"), tuple("jodie", "variable", "winter", "summer"))
);

Wir können verschiedene Arten von Transformationen für Tupel verwenden. Zuerst rufen wir einelimit2()-Methode auf, um nur zwei Werte vonTuple3. zu übernehmen. Dann rufen wir eineconcat()-Methode auf, um zwei Tupel zu verketten.

Im Ergebnis erhalten wir Werte vom TypTuple4.

5. Seq

DasSeq-Konstrukt fügt einemStream übergeordnete Methoden hinzu, während häufig die darunter liegenden Methoden verwendet werden.

5.1. Enthält Operationen

Wir können einige Varianten von Methoden finden, die prüfen, ob Elemente inSeq. vorhanden sind. Einige dieser Methoden verwenden eineanyMatch()-Methode aus einerStream-Klasse:

assertTrue(Seq.of(1, 2, 3, 4).contains(2));

assertTrue(Seq.of(1, 2, 3, 4).containsAll(2, 3));

assertTrue(Seq.of(1, 2, 3, 4).containsAny(2, 5));

5.2. Join Operations

Wenn wir zwei Streams haben und diese verbinden möchten (ähnlich einer SQL-Join-Operation von zwei Datasets), ist die Verwendung einer StandardklasseStreamkeine sehr elegante Methode, um dies zu tun:

Stream left = Stream.of(1, 2, 4);
Stream right = Stream.of(1, 2, 3);

List rightCollected = right.collect(Collectors.toList());
List collect = left
  .filter(rightCollected::contains)
  .collect(Collectors.toList());

assertEquals(collect, Arrays.asList(1, 2));

Wir müssenright Stream in einer Liste sammeln, umjava.lang.IllegalStateException: stream has already been operated upon or closed. zu verhindern. Als nächstes müssen wir eine Nebenwirkungsoperation durchführen, indem wir über einefilter Methode auf einerightCollected Liste zugreifen. Es ist eine fehleranfällige und nicht elegante Art, zwei Datensätze zu verbinden.

Glücklicherweise verbergenSeq has useful methods to do inner, left and right joins on data sets. Diese Methoden eine Implementierung davon, die eine elegante API verfügbar macht.

Wir können einen inneren Join mit der MethodeinnerJoin()durchführen:

assertEquals(
  Seq.of(1, 2, 4).innerJoin(Seq.of(1, 2, 3), (a, b) -> a == b).toList(),
  Arrays.asList(tuple(1, 1), tuple(2, 2))
);

Wir können Rechts- und Linksverknüpfungen entsprechend ausführen:

assertEquals(
  Seq.of(1, 2, 4).leftOuterJoin(Seq.of(1, 2, 3), (a, b) -> a == b).toList(),
  Arrays.asList(tuple(1, 1), tuple(2, 2), tuple(4, null))
);

assertEquals(
  Seq.of(1, 2, 4).rightOuterJoin(Seq.of(1, 2, 3), (a, b) -> a == b).toList(),
  Arrays.asList(tuple(1, 1), tuple(2, 2), tuple(null, 3))
);

Es gibt sogar einecrossJoin()-Methode, die es ermöglicht, zwei Datensätze kartesisch zu verbinden:

assertEquals(
  Seq.of(1, 2).crossJoin(Seq.of("A", "B")).toList(),
  Arrays.asList(tuple(1, "A"), tuple(1, "B"), tuple(2, "A"), tuple(2, "B"))
);

5.3. Manipulieren vonSeq

Seq verfügt über viele nützliche Methoden zum Bearbeiten von Elementsequenzen. Schauen wir uns einige davon an.

Wir können einecycle()-Methode verwenden, um wiederholt Elemente aus einer Quellsequenz zu entnehmen. Es wird ein unendlicher Strom erzeugt, daher müssen wir vorsichtig sein, wenn wir Ergebnisse in einer Liste sammeln. Daher müssen wir einelimit()-Methode verwenden, um die unendliche Folge in eine endliche umzuwandeln:

assertEquals(
  Seq.of(1, 2, 3).cycle().limit(9).toList(),
  Arrays.asList(1, 2, 3, 1, 2, 3, 1, 2, 3)
);

Angenommen, wir möchten alle Elemente von einer Sequenz zur zweiten Sequenz duplizieren. Die Methodeduplicate()macht genau das:

assertEquals(
  Seq.of(1, 2, 3).duplicate().map((first, second) -> tuple(first.toList(), second.toList())),
  tuple(Arrays.asList(1, 2, 3), Arrays.asList(1, 2, 3))
);

Der Rückgabetyp einerduplicate()-Methode ist ein Tupel aus zwei Sequenzen.

Nehmen wir an, wir haben eine Folge von ganzen Zahlen und möchten diese Folge mit einem Prädikat in zwei Folgen aufteilen. Wir können einepartition()-Methode verwenden:

assertEquals(
  Seq.of(1, 2, 3, 4).partition(i -> i > 2)
    .map((first, second) -> tuple(first.toList(), second.toList())),
  tuple(Arrays.asList(3, 4), Arrays.asList(1, 2))
);

5.4. Elemente gruppieren

Das Gruppieren von Elementen nach einem Schlüssel mithilfe der API vonStreamist umständlich und nicht intuitiv, da die Methode voncollect()mit einem Kollektor vonCollectors.groupingByverwendet werden muss.

Seq verbirgt diesen Code hinter einergroupBy()-Methode, dieMap zurückgibt, sodass diecollect()-Methode nicht explizit verwendet werden muss:

Map> expectedAfterGroupBy = new HashMap<>();
expectedAfterGroupBy.put(1, Arrays.asList(1, 3));
expectedAfterGroupBy.put(0, Arrays.asList(2, 4));

assertEquals(
  Seq.of(1, 2, 3, 4).groupBy(i -> i % 2),
  expectedAfterGroupBy
);

5.5. Elemente überspringen

Angenommen, wir haben eine Folge von Elementen und möchten Elemente überspringen, während ein Prädikat nicht übereinstimmt. Wenn ein Prädikat erfüllt ist, sollten Elemente in einer resultierenden Reihenfolge landen.

Wir können dafür eineskipWhile()-Methode verwenden:

assertEquals(
  Seq.of(1, 2, 3, 4, 5).skipWhile(i -> i < 3).toList(),
  Arrays.asList(3, 4, 5)
);

Wir können das gleiche Ergebnis mit einerskipUntil()-Methode erzielen:

assertEquals(
  Seq.of(1, 2, 3, 4, 5).skipUntil(i -> i == 3).toList(),
  Arrays.asList(3, 4, 5)
);

5.6. Zipping-Sequenzen

Wenn wir Sequenzen von Elementen verarbeiten, müssen diese häufig in einer Sequenz komprimiert werden.

Diezip()-API, mit der zwei Sequenzen zu einer komprimiert werden können:

assertEquals(
  Seq.of(1, 2, 3).zip(Seq.of("a", "b", "c")).toList(),
  Arrays.asList(tuple(1, "a"), tuple(2, "b"), tuple(3, "c"))
);

Die resultierende Sequenz enthält Tupel von zwei Elementen.

Wenn wir zwei Sequenzen komprimieren, diese aber auf eine bestimmte Weise komprimieren möchten, können wir einBiFunction an einezip()-Methode übergeben, die die Art des Komprimierens von Elementen definiert:

assertEquals(
  Seq.of(1, 2, 3).zip(Seq.of("a", "b", "c"), (x, y) -> x + ":" + y).toList(),
  Arrays.asList("1:a", "2:b", "3:c")
);

Manchmal ist es nützlich, die Sequenz mit einem Index der Elemente in dieser Sequenz über diezipWithIndex()-API zu komprimieren:

assertEquals(
  Seq.of("a", "b", "c").zipWithIndex().toList(),
  Arrays.asList(tuple("a", 0L), tuple("b", 1L), tuple("c", 2L))
);

6. Konvertieren von aktivierten Ausnahmen in nicht aktivierte

Nehmen wir an, wir haben eine Methode, die einen String akzeptiert und eine aktivierte Ausnahme auslösen kann:

public Integer methodThatThrowsChecked(String arg) throws Exception {
    return arg.length();
}

Dann wollen wir Elemente vonStream zuordnen, die diese Methode auf jedes Element anwenden. Es gibt keine Möglichkeit, diese Ausnahme höher zu behandeln, daher müssen wir diese Ausnahme in einermap()-Methode behandeln:

List collect = Stream.of("a", "b", "c").map(elem -> {
    try {
        return methodThatThrowsChecked(elem);
    } catch (Exception e) {
        e.printStackTrace();
        throw new RuntimeException(e);
    }
}).collect(Collectors.toList());

assertEquals(
    collect,
    Arrays.asList(1, 1, 1)
);

Wir können mit dieser Ausnahme nicht viel anfangen, da funktionale Schnittstellen in Java entworfen wurden. In einer catch-Klausel konvertieren wir eine aktivierte Ausnahme in eine nicht aktivierte Ausnahme.

Glücklicherweise gibt es in einem jOOL eineUnchecked-Klasse mit Methoden, die geprüfte Ausnahmen in ungeprüfte Ausnahmen konvertieren können:

List collect = Stream.of("a", "b", "c")
  .map(Unchecked.function(elem -> methodThatThrowsChecked(elem)))
  .collect(Collectors.toList());

assertEquals(
  collect,
  Arrays.asList(1, 1, 1)
);

Wir verpacken einen Aufruf vonmethodThatThrowsChecked() in eineUnchecked.function()-Methode, die die Konvertierung von Ausnahmen darunter behandelt.

7. Fazit

Dieser Artikel zeigt, wie die jOOL-Bibliothek verwendet wird, die der Java-Standard-APIStreamnützliche zusätzliche Methoden hinzufügt.

Die Implementierung all dieser Beispiele und Codefragmente finden Sie inGitHub project - dies ist ein Maven-Projekt, daher sollte es einfach zu importieren und auszuführen sein, wie es ist.