Letztes Mal: Java 8 ~ für jeden und Lambda-Ausdruck ~
Als nächstes folgt die Stream API Edition.
Es handelt sich um eine von Java8 eingeführte API, die die Verarbeitung (Aggregationsoperation) für Arrays und Sammlungen beschreiben kann. Befolgen Sie die nachstehenden Anweisungen für eine Reihe von Elementen.
Es ist völlig anders als das Schreiben in Java7, daher fasse ich es anhand eines Beispiels zusammen.
--Dateienartikel sind "Produktcode, Bestellmenge"
order.csv
BBJ001,300
AES010,20
BBJ005,100
BBJ001,50
DIH999,10
AES010,150
--Dateielemente sollten "Produktcode, Produktname" sein.
item.csv
BBJ001,Kugelschreiber schwarz
BBJ005,Kugelschreiber rot
AES010,Radiergummi
order_collected.csv
DIH999,,10
BBJ005,Kugelschreiber rot,100
BBJ001,Kugelschreiber schwarz,300
BBJ001,Kugelschreiber schwarz,50
AES010,Radiergummi,20
AES010,Radiergummi,150
Wenn Sie dieses Beispiel in Ihren Code einfügen, würde es meiner Meinung nach so aussehen.
Stream <String> java.nio.file.Files # lines (Path)
, um einen Stream mit allen Zeilen in der Datei zu generieren.
Vor Java7 wurden Reader usw. einzeln generiert und gelesen.
Lesen der Java 7-Versionsdatei
BufferedReader reader = new BufferedReader(new FileReader("files/stream/item.csv"));
String line = null;
while ((line = reader.readLine()) != null) {
//Verschiedene Verarbeitung für eine Zeile
}
Jetzt das.
Lesen der Stream-API-Versionsdatei
Stream<String> itemStream = Files.lines(Paths.get("files/stream/item.csv"));
Zerlegen Sie jedes Element des Streams, das im vorherigen Schritt erstellt wurde.
Stream<String[]> itemStream2 = itemStream .map(line -> line.split(","));
<R> Stream<R> map(Function<? super T,? extends R> mapper)
Die Zwischenoperation map
gibt den Stream zurück, der sich aus der Anwendung des Argument-Lambda-Ausdrucks auf jedes Element des Streams ergibt.
Dieses Mal übergeben wir den Lambda-Ausdruck line-> line.split (",")
.
Verarbeiten Sie line.split (",")
für jedes Element line
von Stream <String> itemStream
und Stream vom Typ Stream <String []>
Wurde generiert.
BBJ001,Kugelschreiber schwarz// ⇒ [BBJ001,Kugelschreiber schwarz]
BBJ005,Kugelschreiber rot// ⇒ [BBJ005,Kugelschreiber rot]
・ ・ ・
Wichtig ist, dass ** Stream-Zwischenoperationen Stream ** zurückgeben. Zwischenoperationen und Beendigungsoperationen können mit den Ergebnissen von Zwischenoperationen durchgeführt werden.
Da es schwierig ist, den Stream so zu behandeln, wie er in der späteren Zuweisung des Produktnamens angegeben ist, konvertieren Sie ihn in Map.
Map<String, String> items = itemStream2.collect(Collectors.toMap(item -> item[0], item -> item[1]));
<R,A> R collect(Collector<? super T,A,R> collector)
Die Beendigungsoperation collect
gibt das Ergebnis der Anwendung einer bestimmten Regel (Collector) auf jedes Element von Stream zurück.
Häufig verwendete Regeln sind in [ Collectors
] verfügbar (https://docs.oracle.com/javase/jp/8/docs/api/java/util/stream/Collectors.html).
Hier wird Collector toMap (<Lambda-Ausdruck, der einen Map-Schlüssel erstellt>, <Lambda-Ausdruck, der einen Map-Wert erstellt>)
verwendet, der eine Map zurückgibt.
Da itemStream2 ein Stream von String []
ist, haben wir eine Map mit dem 0. Element des Arrays als Schlüssel und dem 1. Element als Wert generiert.
** Zwischenoperationen von Stream geben Stream zurück **, sodass Sie in einer Kette von der Stream-Erstellung bis zur Map-Konvertierung schreiben können.
//Produktnamensdatei lesen
Map<String, String> items = Files.lines(Paths.get("files/stream/item.csv") // Stream<String>
//Konvertieren Sie eine Dateizeile in ein Array(Vorbereitung für die Karte)
.map(line -> line.split(",")) // Stream<String[]>
//In Karte konvertieren
.collect(Collectors.toMap(item -> item[0], item -> item[1])); // Map<String, String>
Als nächstes beginnen wir mit der Verarbeitung der Bestelldatei. Es ist bis zum Punkt, an dem eine Datenzeile zerlegt wird, dasselbe wie der Produktnamenstamm.
Stream<String> orderStream = Files.lines(Paths.get("files/stream/order.csv"))
Stream<OrderDto> orderStream2 = orderStream
//Konvertieren Sie eine Dateizeile in ein Array(Vorbereitung für Dto)
.map(line -> line.split(","))
//Array in Delivery Dto konvertieren
.map(array -> makeOrder(array));
Nach dem Teilen mit "," habe ich OrderDto mit makeOrder (String [])
zugeordnet.
private static OrderDto makeOrder(String[] array) {
OrderDto order = new OrderDto();
int idx = 0;
order.setItemCode(array[idx++]);
order.setOrderNum(Integer.parseInt(array[idx++]));
return order;
}
Sortieren nach aufsteigender Reihenfolge des Produktcodes.
Stream<OrderDto> orderStream3 = orderStream2.sorted((item1, item2) -> item1.getItemCode().compareTo(item2.getItemCode()));
Stream<T> sorted(Comparator<? super T> comparator)
Comparator
definiert Vergleichsregeln zwischen Objekten Es ist eine funktionale Schnittstelle.
Wenn Sie die Schnittstelle Comparable
implementieren, hat sie keine ArgumenteSie können auch
sortiert ()
verwenden.
Sie können eine Standardsortierreihenfolge in der Schnittstelle Comparable
festlegen und diese bei Bedarf mit Comparator
in einem Lambda-Ausdruck präzise neu definieren.
Durchsuchen Sie die Produktkarte nach Produktcode. Wenn dies der Fall ist, geben Sie den Produktnamen ein. Wenn dies nicht der Fall ist, geben Sie die Leerzeichen ein.
Stream<OrderDto> orderStream4 = orderStream2.map(order -> {
order.setItemName(Optional.ofNullable(items.get(order.getItemCode())).orElse(""));
return order;
});
Verwenden Sie die Karte erneut. Optional wird hier nicht im Detail erläutert, es wird jedoch als Funktion verwendet, um den Standardwert zu bestimmen, wenn er Null ist.
Nachdem die Daten vollständig sind, geben Sie sie in eine Datei aus.
try (BufferedWriter writer = new BufferedWriter(new FileWriter("files/stream/order_collected.csv")) ) {
orderList.forEach(order -> {
try {
writer.write(makeLine(order));
writer.newLine();
} catch (IOException e) {e.printStackTrace();return;}
});
}
void forEach(Consumer<? super T> action)
Die in der vorherigen Erläuterung des Lambda-Ausdrucks verwendete Beendigungsoperation forEach
führt die durch das Argument für jedes Element angegebene Operation aus.
public class StreamMain {
public static void main(String[] args) {
try (Stream<String> orderStream = Files.lines(Paths.get("files/stream/order.csv"));
Stream<String> itemStream = Files.lines(Paths.get("files/stream/item.csv"))){
//Bestelldatei lesen
Map<String, String> items = itemStream
//Konvertieren Sie eine Dateizeile in ein Array(Vorbereitung für die Karte)
.map(line -> line.split(","))
//In Karte konvertieren
.collect(Collectors.toMap(item -> item[0], item -> item[1]));
//Produktnamensdatei lesen
Stream<OrderDto> orderList = orderStream
//Konvertieren Sie eine Dateizeile in ein Array(Vorbereitung für Dto)
.map(line -> line.split(","))
//Array in Delivery Dto konvertieren
.map(array -> makeOrder(array))
//Sortieren
.sorted((item1, item2) -> item1.getItemCode().compareTo(item2.getItemCode()))
//passend
.map(order -> {
order.setItemName(Optional.ofNullable(items.get(order.getItemCode())).orElse(""));
return order;
});
//Ausgabe
try (BufferedWriter writer = new BufferedWriter(new FileWriter("files/stream/order_collected.csv")) ) {
orderList.forEach(order -> {
try {
writer.write(makeLine(order));
writer.newLine();
} catch (IOException e) {e.printStackTrace();return;}
});
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static String makeLine(OrderDto order) {
StringBuilder line = new StringBuilder();
line.append(order.getItemCode());
line.append(',');
line.append(order.getItemName());
line.append(',');
line.append(order.getOrderNum());
return line.toString();
}
private static OrderDto makeOrder(String[] array) {
OrderDto order = new OrderDto();
int idx = 0;
order.setItemCode(array[idx++]);
order.setOrderNum(Integer.parseInt(array[idx++]));
return order;
}
}
Bei der Lösung des Beispiels habe ich zuerst die Prozedur organisiert.
- Lesen Sie den Produktnamenstamm
- Teilen Sie eine Zeile in Produktcode und Produktnamen auf
- Schlüssel: Produktcode, Wert: Karte des Produktnamens
Wahrscheinlich wird in Java7 oder früherem Code zum Zeitpunkt der for-Schleife sogar Map generiert, um den Produktnamenstamm zu lesen.
Java7
for (/*Satz von Elementen*/) {
//Verschiedene Verarbeitung für ein Element
}
Die Stream-API arbeitet übrigens mit einer Reihe von Elementen.
Typische Operationen sind map
(konvertiere ein Element in ein anderes Element), filter
(extrahiere diejenige, die die Bedingungen aus den Elementen erfüllt / diesmal nicht verwendet), `` sortiertZum Beispiel
(Elemente sortieren).
Da der Rückgabewert der Zwischenoperation Stream ist, ist es außerdem geeignet, zuerst einen Satz von Elementen zu erstellen und dann kontinuierlich zu arbeiten.
Java8
Stream obj = //Konvertieren Sie eine Reihe von Elementen in Stream
//Elemente in obj konvertieren
.map(/*Konvertierungsregeln*/)
//Filtern
.filter(/*Extraktionsregeln*/);
Wenn Sie die Stream-API verwenden, sollten Sie über die Prozedur nachdenken, damit es sich um eine Kombination einfacher Operationen an den Elementen handelt.
Der folgende Artikel war sehr hilfreich. Java8-ähnlichen Code in Java8 schreiben
Ich wollte die Gesamtbestellmenge für jeden Produktcode ermitteln, gab jedoch auf, weil ich nicht herausfinden konnte, wie ich sie gut schreiben sollte. Ich werde den Gedenkcode der Version hinterlassen, die ich erzwungen habe. Bitte lassen Sie mich wissen, wenn Sie gute Hände haben.
//Produktnamensdatei lesen
Stream<OrderDto> orderList = orderStream
//Konvertieren Sie eine Dateizeile in ein Array(Vorbereitung für Dto)
.map(line -> line.split(","))
//Array in Delivery Dto konvertieren
.map(array -> makeOrder(array));
//Gruppieren nach Produktcode für die Aggregation
Map<String, List<OrderDto>> grouping = orderList.collect(Collectors.groupingBy(order->order.getItemCode()));
//Summieren Sie die Bestellmenge für jedes gruppierte Element
orderList = grouping.values()
.stream()
.map(orders->{
//Nimm eines der Elemente auf
OrderDto order = orders.stream().findAny().get();
//Speichern Sie die Gesamtzahl aller Elemente in der Bestellmenge
order.setOrderNum(orders.stream().mapToInt(oo ->oo.getOrderNum()).sum());
return order;
})
//Sortieren
.sorted((item1, item2) -> item1.getItemCode().compareTo(item2.getItemCode()))
//Stellen Sie den Produktnamen ein
.map(order -> {
order.setItemName(Optional.ofNullable(items.get(order.getItemCode())).orElse(""));
return order;
});
Recommended Posts