11

I wish to replace the code below using java8 .stream() or .foreach(). However I am having trouble doing this.

Its probably very easy, but I'm finding the functional way of thinking a struggle :)

I can iterate, no problem but the but returning the modified string is the issue due to mutability issues.

Anyone have any ideas ?

List<String> toRemove = Arrays.asList("1", "2", "3");
String text = "Hello 1 2 3";

for(String item : toRemove){
    text = text.replaceAll(item,EMPTY);
}

Thanks !

Stuart Marks
  • 127,867
  • 37
  • 205
  • 259
SteveG
  • 183
  • 1
  • 3
  • 9

5 Answers5

35

Since you can’t use the stream to modify the text variable you have to coerce the operation into one Function which you can apply to the text to get the final result:

List<String> toRemove = Arrays.asList("1", "2", "3");
String text = "Hello 1 2 3";
text=toRemove.stream()
             .map(toRem-> (Function<String,String>)s->s.replaceAll(toRem, ""))
             .reduce(Function.identity(), Function::andThen)
             .apply(text);
Holger
  • 285,553
  • 42
  • 434
  • 765
16

Wow, you guys like doing things the hard way. this is what filter() and collect() are for.

List<String> toRemove = Arrays.asList("1", "2", "3");
String text = "Hello 1 2 3";

text = Pattern.compile("").splitAsStream(text)
    .filter(s -> !toRemove.contains(s))
    .collect(Collectors.joining());
System.out.println("\"" + text + "\"");

outputs (as the original code did)

"Hello   "

Of course, if your search strings are longer than one character, the previous method works better. If you have a tokenized string, though, split and join is easier.

List<String> toRemove = Arrays.asList("12", "23", "34");
String text = "Hello 12 23 34 55";
String delimiter = " ";

text = Pattern.compile(delimiter).splitAsStream(text)
    .filter(s -> !toRemove.contains(s))
    .collect(Collectors.joining(delimiter));
System.out.println("\"" + text + "\"");

outputs

"Hello 55"
Steve K
  • 4,863
  • 2
  • 32
  • 41
  • Excellent! That looks the best solution so far. I'm getting the grips of things now. Nice work ! – SteveG Dec 03 '14 at 20:50
  • 5
    Except that creating a temporary array via `String.split` holding all elements is exactly the opposite of using the `Stream` API. It could be a good answer if it was using [`Pattern.compile(delimiter).splitAsStream(text)`](http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html#splitAsStream-java.lang.CharSequence-), still not exactly what the question was about, but never mind. – Holger Dec 04 '14 at 10:11
  • It will also be significantly more efficient if you have a list of more than a few items to remove to store them as a Set rather than a List since .contains() on a Set is far more efficient. – Steve K Feb 18 '16 at 23:26
10
text = toRemove.stream()
               .reduce(text, (str, toRem) -> str.replaceAll(toRem, ""));

would work for you.

Rohan Kumar
  • 40,431
  • 11
  • 76
  • 106
yuba
  • 101
  • 1
  • 6
2

If I understood you correctly, you want to do something like this:

toRemove.forEach(removeString -> {
    text = text.replaceAll(removeString, "");
});

The only problem is, that you can't. :(

You can read about it here: http://javarevisited.blogspot.co.il/2014/02/10-example-of-lambda-expressions-in-java8.html

Section 6: One restriction with lambda expression is that, you can only reference either final or effectively final local variables, which means you cannot modified a variable declared in the outer scope inside a lambda.

EDIT

You can do something very ugly. Like this:

private static String text;

public void main (String[] args) {
    text = "Hello 1 2 3";
    List<String> toRemove = Arrays.asList("1", "2", "3");
    toRemove.forEach(removeString -> replaceTextWithEmptyString(removeString));
}

private static void replaceTextWithEmptyString(String whatToReplace) {
    text = text.replaceAll(whatToReplace, "");
}
Michael
  • 1,209
  • 2
  • 12
  • 25
0
List<String> versions = new ArrayList<>();
    versions.add("Lollipop");
    versions.add("KitKat");
    versions.add("Jelly Bean");
    versions.add("Ice Cream Sandwidth");
    versions.add("Honeycomb");
    versions.add("Gingerbread");

    System.out.println("Data");
    versions.stream().filter(s -> s.startsWith("G")).map(i->i.replace("G", "bn")).forEach(System.out::println);

}
sai
  • 1
  • 2