Ten kod działa (pobrany w Javadoc):
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
String commaSeparatedNumbers = numbers.stream()
.map(i -> i.toString())
.collect(Collectors.joining(", "));
Tego nie można skompilować:
int[] numbers = {1, 2, 3, 4};
String commaSeparatedNumbers = Arrays.stream(numbers)
.map((Integer i) -> i.toString())
.collect(Collectors.joining(", "));
IDEA mówi mi, że mam „niezgodny ciąg typu zwracanego w wyrażeniu lambda”.
Czemu ? Jak to naprawić?
java
functional-programming
java-8
java-stream
Denys Séguret
źródło
źródło
IntStream
iStream<Integer>
?IntStream
to specjalizacja strumienia dlaint
wartości pierwotnych . AStream<Integer>
to po prostu strumień zawierającyInteger
obiekty.IntStream
to strumień lub prymitywy (ints), podczas gdySteram<Integer>
jest to strumień obiektów. Strumienie pierwotne mają wyspecjalizowane metody ze względu na wydajność.IntStream.mapToObj
oczekujeIntFunction
funkcji, która zużywaint
wartość, dlatego.mapToObj((Integer i) -> i.toString())
nie działa. I tak nie byłby zalecany, ponieważ zawiera niepotrzebną konwersję zint
naInteger
. W przeciwieństwie do tego.mapToObj(Integer::toString)
działa ładnie, ponieważ wywołastatic
metodęInteger.toString(int)
. Zauważ, że różni się to od wywołania.map(Integer::toString)
a,Stream<Integer>
ponieważ ten ostatni nie skompiluje się, ponieważ jest niejednoznaczny..map(Integer::toString)
na zasadzieStream<Integer>
jest naprawdę dwuznaczne jak zarówno.map(i->i.toString())
i.map(i->Integer.toString(i))
są ważne. Ale można to łatwo rozwiązać za pomocą.map(Object::toString)
.Arrays.stream(numbers)
tworzyIntStream
pod maską, a operacja na mapieIntStream
wymagaIntUnaryOperator
(tj. funkcjiint -> int
). Funkcja mapowania, którą chcesz zastosować, nie jest zgodna z tym kontraktem, a zatem błąd kompilacji.Musisz zadzwonić
boxed()
wcześniej, aby uzyskaćStream<Integer>
(to jest to, coArrays.asList(...).stream()
zwraca). Następnie po prostu zadzwoń,map
tak jak w pierwszym fragmencie.Zauważ, że jeśli potrzebujesz,
boxed()
a następniemap
prawdopodobnie chcesz użyćmapToObj
bezpośrednio.Zaletą jest to, że
mapToObj
nie wymaga pakowania każdejint
wartości doInteger
obiektu; oczywiście w zależności od zastosowanej funkcji mapowania; więc wybrałbym tę opcję, która również jest krótsza do napisania.źródło
Możesz utworzyć strumień całkowity za pomocą Arrays.stream (int []), możesz wywołać
mapToObj
takie jakmapToObj(Integer::toString)
.String csn = Arrays.stream(numbers) // your numbers array .mapToObj(Integer::toString) .collect(Collectors.joining(", "));
Mam nadzieję że to pomoże..
źródło
Bez boksu, AFAIK i bez eksplozji małych sznurków dodanych do stosu:
public static void main(String[] args) { IntStream stream = IntStream.of(1, 2, 3, 4, 5, 6); String s = stream.collect(StringBuilder::new, (builder, n) -> builder.append(',').append(n), (x, y) -> x.append(',').append(y)).substring(1); System.out.println(s); }
źródło
Jeśli celem tego przykładu i pytania jest ustalenie, jak odwzorować ciągi znaków na strumień liczb całkowitych (na przykład użycie strumienia liczb całkowitych w celu uzyskania dostępu do indeksu w tablicy ciągów), możesz również użyć boksu, a następnie rzutować int (co umożliwiłoby wtedy dostęp do indeksu tablicy).
int[] numbers = {0, 1, 2, 3}; String commaSeparatedNumbers = Arrays.stream(numbers) .boxed() .map((Integer i) -> Integer.toString((int)i)) .collect(Collectors.joining(", "));
Wywołanie .boxed () konwertuje Twój IntStream (strumień pierwotnych liczb całkowitych) na Stream (strumień obiektów - mianowicie obiekty typu Integer), który następnie zaakceptuje zwrot obiektu (w tym przypadku obiektu String) z twoja lambda. Tutaj jest to po prostu ciąg znaków reprezentujący liczbę do celów demonstracyjnych, ale równie łatwo (i bardziej praktycznie) mógłby to być dowolny obiekt ciągu - taki jak element tablicy ciągów, jak wspomniano wcześniej.
Pomyślałem, że zaoferuję inną możliwość. W programowaniu zawsze istnieje wiele sposobów wykonania zadania. Poznaj tyle, ile możesz, a następnie wybierz ten, który najlepiej pasuje do danego zadania, mając na uwadze kwestie wydajności, intuicyjność, przejrzystość kodu, preferencje dotyczące stylu kodowania i najbardziej samodokumentujące się.
Miłego kodowania!
źródło
int
do jego typu opakowaniaInteger
i rozpakowujesz go zaraz potem.