2

I am trying to write the equivalent of the following using Java 8 ForEach to encode an array of Strings.

public static void encode(String... stringsToEncode) {
  for (int i = 0; i < stringsToEncode.length; i++) {
     stringsToEncode[i] = URLEncoder.encode(stringsToEncode[i], "UTF-8");
  }
}
// stringsToEncode = 10+111569+++8 as expected.

I have implemented the following:

public static void encodeUsingForEach(String... stringsToEncode)
  List<String> listOfStrings = Arrays.asList(stringsToEncode);
  listOfStrings.forEach(s -> {
    try {
      s = URLEncoder.encode(s, "UTF-8");
  } catch (UnsupportedEncodingException e) {
      throw new AssertionError("UTF-8 is unknown");
    }
 });
}
// listOfStrings = [10 11, 156, 9   8]

What am I missing so that the output of encodeUsingForEach() is equivalent to that of the encode() method?

fuzzi
  • 1,967
  • 9
  • 46
  • 90

2 Answers2

3

You can't replace a value using forEach(), because it only consumes objects without returning them. The reassignment inside the lambda effectively does nothing because arguments are passed by value in Java. Instead, try using a stream to map the values and produce a new list:

List<String> listOfStrings = Arrays.stream(stringsToEncode)
        .map(s -> {
            try {
                return URLEncoder.encode(s, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                throw new AssertionError("UTF-8 is unknown");
            }
        })
        .collect(Collectors.toList());
shmosel
  • 49,289
  • 6
  • 73
  • 138
  • Just as a note, instead of using `"UTF-8"` a more flexible way would be to use the corresponding constant defined in `StandardCharsets.UTF_8` ([documentation](https://docs.oracle.com/javase/8/docs/api/java/nio/charset/StandardCharsets.html)) inside the package `java.nio.charset.StandardCharsets`. – Zabuzard Aug 23 '17 at 02:26
  • 1
    @Zabuza Unfortunately, `URLEncoder` doesn't accept a `Charset` object. – shmosel Aug 23 '17 at 02:27
  • 1
    Oh, what a pity. – Zabuzard Aug 23 '17 at 02:28
  • 1
    @Zabuza Yeah, I'm surprised it hasn't been updated. I suppose you could still use `StandardCharsets.UTF_8.name()`, but no way to avoid that ugly try/catch. – shmosel Aug 23 '17 at 02:28
  • Could you add an explanation why the code of OP does not work? I mean it compiles and I could imagine that he is confused why the lambda doesn't do its job. – Zabuzard Aug 23 '17 at 02:30
  • 2
    @Zabuza It's hard to know why OP thinks it should work, but I've added a bit of explanation. – shmosel Aug 23 '17 at 02:38
  • More sugar to the rescue (method reference)! List listOfStrings = Arrays.stream(stringsToEncode).map(this::encode).collect(Collectors.toList()); `private String encode(String s) { try { return URLEncoder.encode(s, "UTF-8"); } catch (UnsupportedEncodingException e) { throw new AssertionError("UTF-8 is unknown"); } }` – Arul Dhesiaseelan Aug 23 '17 at 02:48
1

In lambda expression the s is one of the members of the list and list is pointing to that location in the memory. So if the s was an object and you changed some fields of that every thing would go right way but now you are replacing the address of object stored in s without updating in the list. So by doing this replacement you are just losing the refrence nothing more.

ConductedClever
  • 4,175
  • 2
  • 35
  • 69