最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Using streams().reduce to build a string from ArrayList<Integer>? - Stack Overflow

programmeradmin2浏览0评论

In JavaScript we can build a string with other types using reducer (e.g. num to string):

const string = [1,2,3,4,5].reduce((acc,e) => acc += e, "") //"12345"

In Java, this pattern is not as easy when building a string from other types:

ArrayList<Integer> arrayListOfIntegers = (ArrayList<Integer>) Arrays.asList(1,2,3,4);
String string = arrayListOfIntegers.stream().reduce("", (String acc, Integer e) -> acc += e); // acc += e throws error

The error is:

"Bad return type: String cannot be converted to integer"

Is this pattern not possible in Java?

In JavaScript we can build a string with other types using reducer (e.g. num to string):

const string = [1,2,3,4,5].reduce((acc,e) => acc += e, "") //"12345"

In Java, this pattern is not as easy when building a string from other types:

ArrayList<Integer> arrayListOfIntegers = (ArrayList<Integer>) Arrays.asList(1,2,3,4);
String string = arrayListOfIntegers.stream().reduce("", (String acc, Integer e) -> acc += e); // acc += e throws error

The error is:

"Bad return type: String cannot be converted to integer"

Is this pattern not possible in Java?

Share Improve this question edited Mar 30, 2021 at 5:33 mplungjan 178k28 gold badges181 silver badges240 bronze badges asked Mar 30, 2021 at 5:32 DavidDavid 1311 silver badge4 bronze badges 2
  • Java is a strongly typed language where you can't just mash an integer into a string and expect the piler to know whether you mean concatenation or addition. Also, if you read the JavaDoc for Stream.reduce you'll see that all parameters involved must be of same type. So you need to map the Integer to a String before you can reduce it into a string. – Torben Commented Mar 30, 2021 at 5:41
  • 3 Using += is an obfuscation. Your actual intention is (acc, e) -> acc + e but your choice to use += instead will lead to a pointless modification of the acc parameter variable which will never be read again. Besides that, in Java you would need reduce("", (acc,e) -> acc + e, (s1,s2) -> s1 + s2). This works, but is horribly inefficient for streams with lots of elements. Use map(String::valueOf).collect(Collectors.joining()) when you prefer simplicity, or collect(StringBuilder::new, StringBuilder::append, StringBuilder::append) .toString() for highest efficiency. – Holger Commented Mar 31, 2021 at 11:08
Add a ment  | 

5 Answers 5

Reset to default 12

In Java, you can simply collect the Stream using Collectors.joining

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<Integer> arrayListOfIntegers = Arrays.asList(1, 2, 3, 4);
        String str = arrayListOfIntegers.stream().map(String::valueOf).collect(Collectors.joining());
        System.out.println(str);
    }
}

Output:

1234

Your are trying to reduce a list of Integers to a String. First map those Integers to Strings and then reduce:

List<Integer> list = Arrays.asList(1,2,3,4);
String value = list.stream()
                   .map(String::valueOf)
                   .reduce("", String::concat);

Instead of (acc,e) -> acc+e you could use String::concat. Also, the type is not pulsory in the lambda expression.

I suppose the best way is using Collectors.joining provided by @Thomas and @Arvind Kumar Avinash. But as a alternative solution I can suggest to use collect method and StringBuilder class, it doesn't generate new String object every time as in reduce case:

List<Integer> list = Arrays.asList(1,2,3,4);
String value = 
       list.stream()
           .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
           .toString();

I suggested this code:

public static void main(String[] args) {
    List<Integer> arrayListOfIntegers = Arrays.asList(1,2,3,4);
    String string = arrayListOfIntegers.stream().reduce("",(sum,elm)-> sum += elm.toString(),(sum1,sum2) -> sum1+sum2);
    System.out.println(string);
}

Among few other options, here is my contribution, when you have list of int i.e primitive values please use [IntStream][1] here is how i have tried to do it. rangeClosed is inclusive of the last number. mapToObj is a intermediate and collect is a terminal operation.

import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class SampleIntStream {
    public static void main(String[] args) {
        System.out.println(getComposedString(1, 5));
    }

    public static String getComposedString(int from, int to) {
        return IntStream
                .rangeClosed(from, to)
                .mapToObj(String::valueOf)
                .collect(Collectors.joining());
    }
}
发布评论

评论列表(0)

  1. 暂无评论