--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 ".
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".
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")
}
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
map (...)
)collect (...)
)Es wird klarer, dass es lesbarer wird.
forEach
kann alles und ist nützlich, aber überlegen Sie, ob es eine andere geeignete Methode gibt.
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.
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.
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
rateInfo.get ()
zu überprüfen, aber dieser Code kann durch statische Analyse abgespielt werden.Es gibt Verdienste wie.
__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.
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üfungEinige ä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.
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.
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");
...
...
}
――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