Witam,
Jeżeli chcę wykonać na streamie jakąś metodę np. void intro() dokładnie raz, to peek(object->intro), czy isynieje lepsze rozwiązanie? Dzięki.
Co to znaczy tylko raz na streamie? Jak masz w strumieniu 10 elementów, to peek() wykona się 10 razy
Dzięki. A jak chcę wykonać cos raz? Mam taki stream np.:
fileContent.stream().skip(1)
.map(values -> mapper.buildObject(headers, values))
i chciałbym jakąś metodę wykonać na nim dokładnie raz?
To już jakiś zły design jest, ale możesz dać idą w peeku
Nie bardzo rozumiem co chcesz osiągnąć. Chcesz wywołać metodę tylko na 1 elemencie strumienia? o_O No mozesz zrobić tam peek, ale to jest jakiś mocno zrypany design.
Generalnie peek()
jest do debugowania nie do przetwarzania danych.
Może tak, choć nie do końca rozumiem o co OPowi chodzi:
stream.limit(1).forEach(el -> el.foo());
Stream powinien być zakończony operacją terminalną peek()
taką operacją nie jest więc może się nie wykonać.
Można też tak:
stream.findAny().ifPresent(el -> el.foo());
JajkoJajeczny napisał(a):
Dzięki. A jak chcę wykonać cos raz? Mam taki stream np.:
fileContent.stream().skip(1)
.map(values -> mapper.buildObject(headers, values))
i chciałbym jakąś metodę wykonać na nim dokładnie raz?
Zgaduje problem.
Czytasz z pliku CSV i w pierwszym wierszu masz headery które chcesz wczytać
Zgaduje rozwiązanie.
Pomysł pierwszy - prosty. Utwórz dwa streamy. Z pierwszego wczytaj tylko header, z drugiego resztę.
Pomysł drugi - szalony. Ponumeruj wszystkie elementy w streamie i wykonaj akcje w zależności od indeksu elementu.
Jak ponumerować elementy?
Po pierwsze potrzebujesz nieskończonego streamu liczb. coś w rodzaju IntStream.iterate(0, i -> i + 1);
Po drugie potrzebujesz metody zip i krotek - Streams .zip(indexStream, lineStream, (index, line) -> Pair.of(index,line)
Po trzecie potrzebujesz przekombinowanego mapowania - `map(pair -> pair.left() == 0 ? intro(pair.right()) : mapper.buildObject(headers,pair.right()))
Po czwarte to się nie uda bo się typy rozjadą, ale może po przeróbkach będzie Ci do czegoś przydatne :(
Duże dzięki. Fajni jesteście..
KamilAdam napisał(a):
Pomysł drugi - szalony. Ponumeruj wszystkie elementy w streamie i wykonaj akcje w zależności od indeksu elementu.
Pomysł trzeci, czyli jeszcze bardziej szalony - napisz własny Collector.
package csv;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
public class CsvCollector<T> implements Collector<String, CsvCollector.CsvData<T>, CsvCollector.CsvData<T>> {
private final Function<String, T> mapper;
private final String delimeter;
private AtomicBoolean readHeaders = new AtomicBoolean(true);
public CsvCollector(Function<String[], T> lineMapper, String delimeter) {
Function<String, String[]> delimFunction = (s -> s.split(delimeter));
this.delimeter = delimeter;
this.mapper = delimFunction.andThen(lineMapper);
}
@Override
public synchronized Supplier<CsvCollector.CsvData<T>> supplier() {
return () -> new CsvData<>();
}
@Override
public BiConsumer<CsvData<T>, String> accumulator() {
return (csvData, line) -> {
if (readHeaders.getAndSet(false)) {
csvData.headers = line.split(delimeter);
} else {
csvData.data.add(mapper.apply(line));
}
};
}
@Override
public BinaryOperator<CsvData<T>> combiner() {
return ((csvData, csvData2) -> {
csvData.data.addAll(csvData2.data);
if (csvData2.headers != null) {
csvData.headers = csvData2.headers;
}
return csvData;
});
}
@Override
public Function<CsvData<T>, CsvData<T>> finisher() {
return Function.identity();
}
@Override
public Set<Characteristics> characteristics() {
return Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
}
public static class CsvData<T> {
private final List<T> data = new ArrayList<>();
private String[] headers;
public List<T> getData() {
return data;
}
public String[] getHeaders() {
return headers;
}
}
}
package csv;
import java.util.Arrays;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Test {
private final static String[] lines = {"First;Second", "1;2", "3;4"};
public static void main(String[] args) {
CsvCollector.CsvData<Integer[]> result = Stream.of(lines)
.collect(new CsvCollector<>(Test::parseLine, ";"));
System.out.println("Headers: " + Arrays.toString(result.getHeaders()));
System.out.println("Lines:\n" + result.getData().stream().map(Arrays::toString).collect(Collectors.joining("\n")));
}
private static Integer[] parseLine(String[] line) {
return Stream.of(line)
.map(Integer::parseInt)
.toArray(Integer[]::new);
}
}
I nie, nie wiem czy bym się odważył zastosować to na produkcji :D
Mega. Dzięki Wartek...