2
String s = "apples for you";
StringBuilder returnString = new StringBuilder("");
Arrays.stream(s.split(" "))
        .reduce(returnString, (acc, str) -> acc.append(str.charAt(0)));

Expected output first letter of each word, i.e. afy.

But getting error at acc.append, acc is treated to be a String.

Community
  • 1
  • 1
Klose
  • 323
  • 5
  • 17

3 Answers3

5

Your use of reduce is incorrect. The overload you intend to call is the one with 3 parameters, which should also take a binary operator for StringBuilder:

StringBuilder returnString = Arrays.stream(s.split(" "))
        .reduce(new StringBuilder(""), 
                (acc, str) -> acc.append(str.charAt(0)), 
                (sb1, sb2) -> sb1.append(sb2));

If you're to use this on a parallel stream, please perform a mutable reduction (with stream.collect) as the initial, identity string builder object may otherwise be appended to unpredictably from multiple threads:

StringBuilder returnString = Arrays.stream(s.split(" "))
        .collect(StringBuilder::new, 
                 (acc, str) -> acc.append(str.charAt(0)), 
                 StringBuilder::append);
ernest_k
  • 44,416
  • 5
  • 53
  • 99
  • 3
    This still is incorrect, as it is modifying the identity value. This will break with a parallel Stream. Either, use `String.concat` with `reduce` or use `collect` with a `StringBuilder` (which will `joining()` give you for free). This is an attempt to perform a [Mutable Reduction](https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/stream/package-summary.html#MutableReduction) and must use the right method for that. – Holger Jan 29 '21 at 19:35
4

ernest_k's answer is correct, of course. It's worth adding, though, that it seems like you're using reduce to implement the joining collector yourself, and might want to use it directly:

String result = 
  Arrays.stream(s.split(" ")).map(x -> x.substring(0, 1)).collect(Collectors.joining());
Mureinik
  • 297,002
  • 52
  • 306
  • 350
1

You can use reduce method with Strings instead of StringBuilder:

String str1 = "apples for you";
String str2 = Arrays
        // split string into an array of words
        .stream(str1.split("\\s+"))
        // first character of a word
        .map(str -> str.charAt(0))
        // character as string
        .map(String::valueOf)
        // reduce stream of strings to a single
        // string by concatenating them
        .reduce((s1, s2) -> s1 + s2)
        // otherwise null
        .orElse(null);

System.out.println(str2); // afy

See also: Using Streams instead of for loop in java 8