Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 removing an item from array/array list based on regex

Tags:

java

java-8

Is there a better way to achieve the following in java 8?

String regex = "^SACHI";
for (String temp : personalNames ) {
    if (temp.matches(regex)){
         personalNames.remove(temp);
    }
}
like image 438
S.Dan Avatar asked Feb 21 '19 08:02

S.Dan


3 Answers

You can use

personalNames.removeIf(Pattern.compile("^SACHI").asPredicate());

You could also use the simpler

personalNames.removeIf(s -> s.matches("^SACHI"));

but it will perform Pattern.compile("^SACHI") under the hood, for every element in the worst case. Note that the Pattern created by compile is immutable and can be shared, hence, you could also create it only once, like

static final Pattern REMOVAL_PATTERN = Pattern.compile("^SACHI");

and use it like

personalNames.removeIf(REMOVAL_PATTERN.asPredicate());

asPredicate() uses find() instead of matches(), but since your pattern has the ^ anchor, it makes no difference. The method asMatchPredicate() for getting a predicate using matches() has been added in JDK 11.


If all you want, is to match a literal string at the beginning, you can also use

personalNames.removeIf(s -> s.startsWith("SACHI"));

which does not have the regex initialization overhead.

like image 142
Holger Avatar answered Oct 25 '22 10:10

Holger


Adding and/or removing elements from an existing container does not fit in nicely with the concepts of functional programming. More over that behavior is not thread safe in parallel and concurrent environment. Making it thread safe demands more effort too. Therefore prefer steteless lambdas to stateful lambdas as a good engineering practice. You can get the matching names by merely using filter operator. Here's how it looks.

private static final Pattern PATTERN = Pattern.compile("^SACHI");

List<String> validNames = personalNames.stream()
    .filter(PATTERN.asPredicate())
    .collect(Collectors.toList());
like image 26
Ravindra Ranwala Avatar answered Oct 25 '22 08:10

Ravindra Ranwala


It depends did you need to modify existing list, or you need just get list without elements. In first case, you can use stream to filter non matching objects and remove them from list

personalNames.removeAll(
        personalNames
                .stream()
                .filter(x -> !x.matches(regex))
                .collect(Collectors.toList())
);

In other case, you can just return new list with only matching objects

final List<String> matchingElements = personalNames.stream()
        .filter(x -> x.matches(regex))
        .collect(Collectors.toList());

also, this code

for (String temp : personalNames ) {
    if (temp.matches(regex)){
        personalNames.remove(temp);
    }
}

will throw java.util.ConcurrentModificationException

like image 43
Patrickoo Avatar answered Oct 25 '22 10:10

Patrickoo