Este código funciona (obtido no Javadoc):
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
String commaSeparatedNumbers = numbers.stream()
.map(i -> i.toString())
.collect(Collectors.joining(", "));
Este não pode ser compilado:
int[] numbers = {1, 2, 3, 4};
String commaSeparatedNumbers = Arrays.stream(numbers)
.map((Integer i) -> i.toString())
.collect(Collectors.joining(", "));
IDEA me diz que tenho um "tipo de retorno incompatível String na expressão lambda".
Por quê ? E como consertar isso?
java
functional-programming
java-8
java-stream
Denys Séguret
fonte
fonte
IntStream
eStream<Integer>
?IntStream
é uma especialização de fluxo paraint
valores primitivos . AStream<Integer>
é apenas um riacho segurandoInteger
objetos.IntStream
é um fluxo ou primitivos (ints) enquantoSteram<Integer>
é um fluxo de objetos. Os fluxos primitivos têm métodos especializados por motivos de desempenho.IntStream.mapToObj
espera umIntFunction
, uma função que consome umint
valor, portanto.mapToObj((Integer i) -> i.toString())
não funciona. De qualquer forma, não seria recomendado, pois contém uma conversão desnecessária deint
paraInteger
. Em contraste,.mapToObj(Integer::toString)
funciona bem porque chama ostatic
métodoInteger.toString(int)
. Observe que isso é diferente de chamar.map(Integer::toString)
a,Stream<Integer>
já que o último não compila porque é ambíguo..map(Integer::toString)
aStream<Integer>
é realmente ambíguo como ambos.map(i->i.toString())
e.map(i->Integer.toString(i))
é válido. Mas é facilmente resolvido usando.map(Object::toString)
.Arrays.stream(numbers)
cria umIntStream
sob o capô e a operação do mapa em umIntStream
requer umIntUnaryOperator
(ou seja, uma funçãoint -> int
). A função de mapeamento que você deseja aplicar não respeita este contrato e, portanto, o erro de compilação.Você precisaria ligar
boxed()
antes para obter umStream<Integer>
(isto é o queArrays.asList(...).stream()
retorna). Em seguida, basta chamarmap
como você fez no primeiro trecho.Observe que, se precisar ser
boxed()
seguido por,map
provavelmente você deseja usarmapToObj
diretamente.A vantagem é que
mapToObj
não requer encaixar cadaint
valor em umInteger
objeto; dependendo da função de mapeamento que você aplica, é claro; então eu escolheria essa opção, que também é mais curta para escrever.fonte
Você pode criar um Integer Stream usando Arrays.stream (int []), você pode chamar
mapToObj
likemapToObj(Integer::toString)
.Espero que isto ajude..
fonte
Sem boxe, AFAIK e sem explosão de pequenas cordas adicionadas à pilha:
fonte
Se o objetivo deste exemplo e pergunta é descobrir como mapear strings para um fluxo de ints (por exemplo, usando um fluxo de ints para acessar um índice em um Array de strings), você também pode usar boxing e, em seguida, lançar para um int (que permitiria acessar o índice do array).
A chamada .boxed () converte seu IntStream (um fluxo de ints primitivos) em um Stream (um fluxo de objetos - ou seja, objetos Integer) que, então, aceitará o retorno de um objeto (neste caso, um objeto String) de seu lambda. Aqui, é apenas uma representação de string do número para fins de demonstração, mas poderia ser tão facilmente (e de forma mais prática) qualquer objeto de string - como o elemento de uma matriz de string, conforme mencionado antes.
Só pensei em oferecer outra possibilidade. Na programação, sempre existem várias maneiras de realizar uma tarefa. Conheça o máximo que puder e, em seguida, escolha aquele que melhor se adapta à tarefa em questão, tendo em mente os problemas de desempenho, intuitividade, clareza de código, suas preferências no estilo de codificação e o que mais se autodocumenta.
Boa codificação!
fonte
int
em seu tipo de invólucroInteger
e desembala logo depois.