Schreiben Sie Java8-ähnlichen Code in Java8

Übersicht (wovon redest du)

--Wenn ich den Code überprüfe, verwende ich Java8-Funktionen (Stream-API, Optional usw.), sehe jedoch häufig Code, der auf die gleiche Weise wie vor Java7 geschrieben wurde. ――Ich möchte, dass jeder __Java8-ähnlichen Code __ schreibt. Es ist eine Verschwendung, wenn nicht. (* Der Standard von "Java 8-ish" ist relativ (ziemlich?) Persönliche Meinung ist enthalten) ――Es ist schwer zu vermitteln, selbst wenn Sie alle Wörter verwenden. Machen wir also ein Beispiel. __ ← dies __ "Lassen Sie uns übrigens ein Beispiel dafür machen," Java 8-Funktionen zwangsweise zu verwenden, was es noch schlimmer macht ".

Zielgruppe

Notice Der Inhalt dieses Artikels ist nichts Neues, und einige andere Sprachen als Java können komplexer geschrieben werden. Dieser Artikel richtet sich an "Personen, die von Java 7 oder früher auf Java 8 migriert sind, aber nicht daran gewöhnt sind, mit Stream und Optional zu schreiben".

Muster, die Java 8-ähnlicher sein können

Es wird davon ausgegangen, dass es ein solches Produktobjekt gibt und eine gewisse Verarbeitung daran durchgeführt wird.

Item.java


//Produktklasse
public class Item {
  String name; //Produktname
  BigDecimal price; //Produktpreis
  String currency; //Preisfeldwährung("JPY"Und"USD")
}

Ersetzen Sie einfach die erweiterte for-Anweisung durch "forEach"

Angenommen, Sie möchten etwas wie "Daten konvertieren und in einer anderen Liste speichern" ausführen. Vor Java7 sieht es aus wie ↓.

Wie schreibe ich vor Java7


//Konvertieren Sie japanische Yen-Produkte in USD
BigDecimal jpyToUsd = BigDecimal.valueOf(100);

List<Item> usdItems = new ArrayList<>();

for(Item jpyItem : jpyItems) {
    Item usdItem = new Item();
    usdItem.setName(jpyItem.getName());
    usdItem.setPrice(jpyItem.getPrice().multiply(jpyToUsd));
    usdItem.setCurrency("USD");
    usdItems.add(usdItem);
}

Als Ergebnis der Meldung "Da es sich um Java 8 handelt, machen Sie es mit Stream, ohne for zu verwenden" wird es so.

nur für jeden


BigDecimal jpyToUsd = BigDecimal.valueOf(100);

List<Item> usdItems = new ArrayList<>();

jpyItems.forEach(jpyItem -> {
    Item usdItem = new Item();
    usdItem.setName(jpyItem.getName());
    usdItem.setPrice(jpyItem.getPrice().multiply(jpyToUsd));
    usdItem.setCurrency("USD");
    usdItems.add(usdItem);
});

Was Sie tun, unterscheidet sich nicht von der erweiterten for-Anweisung. Wenn Sie dies unter Berücksichtigung der "Zwischenoperation" und "Beendigungsoperation" von Stream umschreiben, wird es so.

Java8-ish


BigDecimal jpyToUsd = BigDecimal.valueOf(100);

//Realisiert durch Kombinieren von Karte und Sammeln ohne Verwendung von forEach
List<Item> usdItems = jpyItems.stream()
        .map(jpyItem -> {
            Item usdItem = new Item();
            usdItem.setName(jpyItem.getName());
            usdItem.setPrice(jpyItem.getPrice().multiply(jpyToUsd));
            usdItem.setCurrency("USD");

            return usdItem;
        })
        .collect(Collectors.toList());

(* Die Gegenmaßnahmen für die Tatsache, dass der Inhalt der Karte fett ist, werden später beschrieben.)

Auf diese Weise

Es wird klarer, dass es lesbarer wird. forEach kann alles und ist nützlich, aber überlegen Sie, ob es eine andere geeignete Methode gibt.

Lambda ist groß

Im vorherigen Beispiel ist das Lambda in der Karte groß, die Methodenkette des Streams wird lang und das Ganze ist schwer zu sehen und die Lesbarkeit ist gering.

Wenn Sie fragen: "Dann sollte ich Lambda als Variable herausnehmen?"

Lambda variieren


Function<Item,Item> convertToUsdItem = jpyItem -> {
    Item usdItem = new Item();
    usdItem.setName(jpyItem.getName());
    usdItem.setPrice(jpyItem.getPrice().multiply(jpyToUsd));
    usdItem.setCurrency("USD");

    return usdItem;
};

List<Item> usdItems = jpyItems.stream()
    .map(convertToUsdItem)
    .collect(Collectors.toList());

Der Stream wird immer noch aktualisiert, ist jedoch weniger testbar, wenn Sie die Verarbeitung von "convertToUsdItem" testen möchten. Daher ist es bequemer, eine normale Methode zu verwenden, und es ist einfacher, persönlich zu lesen. (Es kann Geschmackssache in Bezug auf die Lesbarkeit sein)

Als normale Methode ausschneiden


public Item convertToUsdItem(Item jpyItem) {
    Item usdItem = new Item();
    usdItem.setName(jpyItem.getName());
    usdItem.setPrice(jpyItem.getPrice().multiply(jpyToUsd));
    usdItem.setCurrency("USD");

    return usdItem;
}

List<Item> usdItems = jpyItems.stream()
    .map(this::convertToUsdItem)
    .collect(Collectors.toList());

Mithilfe von Methodenreferenzen können Sie einen Stream so einfach wie ein Lambda schreiben.

Ich verwende nur einige Felder des Zielobjekts, aber ich bin keine "Karte"

Wenn ich beispielsweise einen Prozess wie "Ausgabe des Produktnamens als Standard für Produkte, deren Produktname mit" A "beginnt" betrachte, sehe ich manchmal einen Code wie diesen.

python


items.steam()
    .filter(item -> item.getName().startsWith("A"))
    .forEach(item -> System.out.println(item.getName()));

Da Sie nur den Produktnamen verwenden möchten, müssen Sie das Artikelobjekt nicht bis zum Ende weiterleiten. Daher ist es einfacher, das Namensfeld zuerst mit der Karte zu extrahieren.

Extrahieren Sie nur den Namen mit Karte und Prozess


items.stream()
    .map(Item::getName)
    .filter(name -> name.startsWith("A"))
    .forEach(System.out::println);

Auf diese Weise

—— Sie können frühzeitig verstehen, dass „nur Produktnamen behandelt werden“.

Es gibt Verdienste wie.

Ich habe eine Methode erstellt, die null zurückgibt und vom Aufrufer auf null überprüft

Wenn Sie den Rückgabewert von findFirst der Stream-API verarbeiten oder eine Methode der Java 8-Bibliothek verwenden, die Optional zurückgibt, müssen Sie Optional verwenden, unabhängig davon, ob. Als ich gerade Java8 lernte, scheint es jedoch, dass ich beim Versuch, eine Methode selbst zu implementieren, oft nicht denke, dass wir den Rückgabetyp auf Optional setzen sollen.

Angenommen, Sie erstellen eine Methode, die "Wechselkursinformationen aus dem Cache abruft und den Standardwert (1) zurückgibt, wenn der Cache nicht vorhanden ist".

Holen Sie sich den Wechselkurs aus Bargeld(Nullversion)



public RateInfo getFromCache(String fromCurrency, String toCurrency) {
    //Gibt das RateInfo-Objekt zurück, wenn es im Cache vorhanden ist, andernfalls null
}

public BigDecimal retrieveRate(String fromCurrency, String toCurrency) {

    RateInfo rateInfo = getFromCache(fromCurrency, toCurrency);

    if(rateInfo != null) {
        return rateInfo.getRate();
    }

    return BigDecimal.ONE;
}

Hier verhält sich die Methode "getFromCache" wie folgt: "Gibt das RateInfo-Objekt zurück, wenn es im Cache vorhanden ist, oder null, wenn es nicht vorhanden ist." Daher ist beim Aufrufer eine if-Anweisung für die Nullprüfung erforderlich. Und manchmal überprüfe ich die Null nicht und es wird schleimig.

Deshalb kommt hier Optional ins Spiel.

Holen Sie sich den Wechselkurs aus Bargeld(Optionale Version)


public Optional<RateInfo> getFromCache(String fromCurrency, String toCurrency) {
    //Das Ergebnis des Versuchs, das RateInfo-Objekt aus dem Cache abzurufen, ist optional<RateInfo>Als Objekt zurückgeben
}

public BigDecimal retrieveRate(String fromCurrency, String toCurrency) {
    Optional<RateInfo> rateInfo = getFromCache(fromCurrency, toCurrency);

    return rateInfo.map(RateInfo::getRate).orElse(BigDecimal.ONE);
}

Auf diese Weise

Es gibt Verdienste wie.

Muster, die nicht gezwungen werden sollten, Java 8-Funktionen zu verwenden

__for und null check Ein Fall, in den man leicht hineinfallen kann, wenn es aussieht wie ein Mann, der __ absolut tötet. Java8s Stream und Optional sind oft nicht so cool wie die anderer Sprachen, und ich bin süchtig danach, sie zu behandeln.

Ersetzen Sie die Anweisung durch den Index durch Stream

Zum Beispiel

für Anweisung mit Index


for(int i=0; i < items.size(); i++) {
    System.out.println(
        String.valueOf(i) + " : " + items.get(i).getName());
}

Als Ergebnis der Begeisterung für die Verarbeitung wie "Ich werde auf die for-Anweisung verzichten!"

Gib dein Bestes mit Stream


//Generierung von Schleifenzählern mit IntStream
IntStream.range(0, items.size())
    .forEach(i -> System.out.println(
        String.valueOf(i) + " : " + items.get(i).getName());

//Geben Sie Ihr Bestes mit Atomic Integer und für jeden
AtomicInteger i = new AtomicInteger();
items.forEach(item -> System.out.println(
        String.valueOf(i.getAndIncrement()) + " : " + item.getName());

Es wird wie. Ersteres soll ursprünglich als Stream-Verarbeitung von Elementen ausgedrückt werden. Da jedoch im IntStream für die Indexgenerierung auf "get (i)" zugegriffen wird, unterscheidet es sich nicht von einer normalen for-Anweisung und ist schwer zu lesen. (Früher habe ich so geschrieben, aber ich habe es aus dem oben genannten Grund gestoppt.)

Letzteres ist das letztere, und "AtomicInteger verwenden, da der primitive Typ int in Lambda nicht inkrementiert werden kann" wird nicht empfohlen, da er von der ursprünglichen Verwendung von AtomicInteger abzuweichen scheint.

Erfassungsvorgang mit Index in Java ([Kotlin's this](http://qiita.com/opengl-8080/items/36351dca891b6d9c9687#indexed%E7%B9%B0%E3%82%8A%E8%BF%94%E3] % 81% 97% E5% 87% A6% E7% 90% 86% E3% 81% AB% E3% 83% AB% E3% 83% BC% E3% 83% 97% E3% 82% A4% E3% 83 % B3% E3% 83% 87% E3% 83% 83% E3% 82% AF% E3% 82% B9% E3% 82% 82% E6% B8% A1% E3% 81% 99)) Ich wünschte, ich könnte es benutzen Leider wurde es noch nicht implementiert, daher scheint es im Moment besser zu sein, die for-Anweisung gehorsam zu verwenden, als die Stream-API zwangsweise zu verwenden.

Optional.ofNullable nur zur Nullprüfung

Einige ältere Bibliotheken und Methoden, die vor Java 7 verfügbar sind, können null als Rückgabewert zurückgeben. Wenn Sie für eine solche Methode nur überprüfen möchten, ob der Rückgabewert null ist, und Sie das Gefühl haben, "Ich schreibe nicht", wenn (a! = Null) "egal was!", Wird der folgende Code angezeigt. Es ist fertig.

Bewerten Sie, indem Sie den Rückgabewert in Optional einschließen



// getText()Kann null zurückgeben
String text = getText();

//Wickeln Sie es in Optional ein und überprüfen Sie es. Verwenden Sie nicht den Wert des Inhalts
if(Optional.ofNullable(text).isPresent()) {
    return "OK";   
}

return "NG";

Es ist in Ordnung, "Optional.isPresent ()" zu verwenden, aber es ist etwas ärgerlich, weil der Code länger ist als die normale Nullprüfung. Ich denke, dass "if (text! = Null)" hier in Ordnung ist.

Ein wenig besorgniserregender Teil der Verwendung wie das Standardargument

Optional wird hauptsächlich als "Rückgabewert einer Methode" als Entwurfskonzept verwendet, und andere Verwendungen (z. B. als Argumenttyp verwendet) werden nicht empfohlen. r.f stackoverflow - Why java.util.Optional is not Serializable, how to serialize the object with such fields

Selbst wenn Sie den optionalen Typ als Argument verwenden, kann das von Ihnen übergebene optionale Objekt null sein, sodass es nicht sehr lecker ist. Das Argument "Ist es nicht möglich, diese Art von Optional zu verwenden?" Hat jedoch etwas zu bedeuten. So wird es wie das Standardargument __ verwendet.

Drücken Sie ein Pseudo-Standardargument mit Optional aus


//Gibt das Zielprodukt zurück, das in den Preis der angegebenen Währung konvertiert wurde
public Item convert(Item item, String toCurrency) {
     //Verwenden Sie USD, wenn keine Währung angegeben ist
     String currency = Optional.ofNullable(toCurrency).orElse("USD");

     ...
     ...
}

Es mag einige Meinungen geben, die "Überladung verwenden", aber da Überladung nicht für die Implementierungsmethode der Schnittstelle der Drittanbieter-Bibliothek verwendet werden kann, die als Rückrufmethode angegeben ist, überlege ich, wie ich sie so verwenden soll.

Nachtrag (30.08.2017)

Wie in Kommentar ausgeführt, ist es möglicherweise besser, eine andere Methode zu verwenden.

Verwenden Sie die Methode "Standardwert wenn null"


//Gibt das Zielprodukt zurück, das in den Preis der angegebenen Währung konvertiert wurde
public Item convert(Item item, String toCurrency) {
     // java.util.Objects.toString
     String currency1 = Objects.toString(toCurrency,"USD");

     // org.apache.commons.lang3.ObjectUtils.defaultIfNull
     String currency2 = ObjectUtils.defaultIfNull(toCurrency, "USD");

     ...
     ...
}

Schließlich

――Es ist interessant, verschiedene Schreibweisen zu untersuchen, da sowohl Stream API als auch Optional effizienter und verständlicher als zuvor geschrieben werden können, anstatt nur eine Methodenklasse hinzuzufügen. ―― Es gibt jedoch viele Teile, die zum Zeitpunkt von Java 8 nicht cool sind. Daher ist es wichtig, nach „genau der richtigen Verwendung“ zu suchen, anstatt sie blind zu verwenden.

Recommended Posts

Schreiben Sie Java8-ähnlichen Code in Java8
Schreiben Sie Flyway-Rückrufe in Java
Java mit Visual Studio Code
Errate den Zeichencode in Java
Java Spring-Umgebung in vs Code
Schreiben Sie den Testcode mit Spring Boot
Führen Sie Java-Code skriptweise aus
Java-Code-TIPPS
Partisierung in Java
Änderungen in Java 11
Janken in Java
Java-Beispielcode 04
Alle gleichen Hash-Code-Zeichenfolgen in Java
Java-Beispielcode 01
Java-Zeichencode
Umfangsrate in Java
[Mac] Installieren Sie Java in Visual Studio Code
FizzBuzz in Java
Fügen Sie in Java in Visual Studio Code die Option --enable-Preview hinzu
Techniken zum Lesen von Java-Quellcode in Eclipse
Führen Sie eine statische Code-Analyse mit Checkstyle mit Java + Gradle durch
Code zum Escapezeichen von JSON-Zeichenfolgen in Java
Versuchen Sie es mit Sourcetrail (Win-Version) mit Java-Code
Schreiben Sie Selenium Java-Bindungscode mit Silk WebDriver
[AtCoder Problem-ABC001] C-Do Windbeobachtung in Java [Code]
Wie schreibe ich Java String # getBytes in Kotlin?
[Java-Anfängerangst] In Junit implementierter schwer zu testender Code
[Mac] Java in Visual Studio Code installieren (VS Code)
Lesen Sie JSON in Java
Interpreter-Implementierung durch Java
Machen Sie einen Blackjack mit Java
Janken App in Java
Einschränkungsprogrammierung in Java
Setzen Sie Java8 in Centos7
Verbinden Sie Arrays in Java
"Hallo Welt" in Java
Aufrufbare Schnittstelle in Java
Kommentare in der Java-Quelle
Azure funktioniert in Java
Formatieren Sie XML in Java
Einfache HTML-Spezialchars in Java
Boyer-Moore-Implementierung in Java
Hallo Welt in Java
Verwenden Sie OpenCV mit Java
WebApi-Memorandum mit Java
Typbestimmung in Java
Befehle in Java ausführen (Ping)
Verschiedene Threads in Java
Zabbix API in Java
ASCII-Kunst in Java
Listen in Java vergleichen
POST JSON in Java
Fehler in Java ausdrücken
Implementieren Sie CustomView im Code
Erstellen Sie JSON in Java
Datumsmanipulation in Java 8
Was ist neu in Java 8?
Verwenden Sie PreparedStatement in Java
Was ist neu in Java 9,10,11
Parallele Ausführung in Java