3

I was checking the java 8 documentation and I found that class Pattern has the method asPredicate.

I was looking through StackOverflow but I've not found anything related with thread safety.

I know that the Pattern class is thread safe as the docs says

Instances of this class are immutable and are safe for use by multiple concurrent threads. Instances of the Matcher class are not safe for such use.

But, what happens with the Predicate generated by asPredicate method?

viticlick
  • 155
  • 1
  • 9
  • 2
    A _predicate_ only provides a value. It doesn't have a state that can be changed. So it is immutable and thus thread-safe. – Seelenvirtuose Jul 12 '19 at 07:28
  • Thread safety is mostly under documented. But this may help: https://stackoverflow.com/questions/1360113/is-java-regex-thread-safe – Ravindra Ranwala Jul 12 '19 at 07:31
  • @Eugene Ah ok. You would have been right, if the `asPredicate` method were indeed a method of `Matcher`. But it isn't! It is a method of `Pattern` which is thread-safe. – Seelenvirtuose Jul 12 '19 at 07:41
  • @Seelenvirtuose just read the question again... sorry about the confusion. – Eugene Jul 12 '19 at 07:41
  • 3
    @Seelenvirtuose Conceptually you are right : a predicate should not have a state and should even not change any state. But a bad usage of it could change the state of object used by the predicate body that could break the thread safety. `asPattern()` is of course not concerned. – davidxxx Jul 12 '19 at 08:22
  • 1
    @davidxxx You are right. I posted my comment in the context of `Pattern` (vs. `Matcher`), realizing afterwards that OP did mess up those two classes. I cannot edit the comment anymore, so I leave it as it is. – Seelenvirtuose Jul 12 '19 at 08:59

2 Answers2

3

Matcher is not thread safe but Pattern is.
About asPredicate() you can consider it thread safe as the Pattern javadoc class itself is defined as safe for use by multiple concurrent threads :

Instances of this class are immutable and are safe for use by multiple concurrent threads. Instances of the Matcher class are not safe for such use.

As underlined by Holger, the Predicate returned by Pattern.asPredicate() is not documented as thread safe (nor the reverse) but the implementation of it proves that it is :

public Predicate<String> asPredicate() {
    return s -> matcher(s).find();
}

Pattern.asPredicate() is just another way to do a match between a String against a pattern similarly to Pattern.matcher(CharSequence).find().

This :

boolean isFound = pattern.matcher(myString).find(); 

can be done in this way :

boolean isFound = pattern.asPredicate().test(myString); 

So here the new thing is that you can pass the predicate in a stream or any method that accepts a predicate. Which makes the intention really clearer : not need to manipulate a Pattern but a Predicate.

Pattern pattern = ...;
...stream().filter(o-> pattern.matcher(o).find());

can be replaced by :

Predicate<String> predicate = pattern.asPredicate();
List<String> strings = ...;
strings.stream().filter(predicate).(...); 
//or
strings.stream().filter(pattern.asPredicate()).(...);
davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • Your example `pattern.matcher(myString).find()` shows that the actual operation has to go through a `Matcher`. Whether the created `Predicate` creates a new `Matcher` each time (which would be thread safe) or creates one and reuses it (which would not), is not specified in Java 8. Thankfully, [JDK 11 contains a clarification](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/regex/Pattern.html#asPredicate()). – Holger Jul 15 '19 at 13:58
  • @Holger That is indeed not specified directly but the Pattern class itself declares : "Instances of this class are immutable and are safe for use by multiple concurrent threads." Safe for use by multiple concurrent thread" supposes that all instance methods are thread safe, so `asPredicate()` is. About JDK 11 javadoc, I suppose that you refer to the part that says "as if it creates a matcher". I find the "as if" formulation a little annoying because ambiguous. – davidxxx Jul 15 '19 at 18:45
  • Yes, an invocation of `asPredicate()` is thread safe per class doc and so is an invocation of `matcher(…)`. But that doesn’t say anything about the returned object, as the `matcher(…)` example demonstrates. Whether the returned `Predicate` is thread safe, can only derived from the statement that it is equivalent to `s -> matcher(s).find()`, but if you consider that too weak, you’d have to revise your answer, as the fact that `Pattern` is thread safe doesn’t say anything about an object using the pattern, like a `Matcher` or the `Predicate` implementation. – Holger Jul 16 '19 at 08:54
  • @Holger interesting, I only deducted this from the implementation; but wouldn't that mean that `Matcher::matcher` has to return a new instance all the time? that is indeed the case, but is _return A new matcher for this pattern_ enough for this?; I guess the word _new_ is taken literally here. – Eugene Jul 16 '19 at 09:16
  • @Eugene you mean `Pattern::matcher`, but yes, “Creates a matcher…” and “@Return A new matcher…” has to be taken literally. Everything else would defeat the purpose of thread safe reusability. As the class doc says, “…so many matchers can share the same pattern”. – Holger Jul 16 '19 at 09:34
  • @Holger I think that it is debatable. I think that if the Predicate returned by `asPredicate()` reused the same `matcher()` or in a general way could cause some inconsistencies in a concurrent usage, to not document the method as no thread safe about the returned `Predicate` would be a serious lack. – davidxxx Jul 16 '19 at 12:17
  • Just to make that clear: I have no doubt that the intention is that the predicate is stateless and works with a parallel stream. But you can’t derive that from the class doc statement that `Pattern` is thread safe. The JDK 11 statement about the equivalence to `s -> matcher(s).find()` (which matches the implementation) is a much stronger statement. By the way, [your last edit](https://stackoverflow.com/revisions/57002433/3) broke the link. – Holger Jul 16 '19 at 12:22
  • @Holger Indeed I mixed a little things. I realized that after sending the comment. That s' why I deleted the example and recreate a new comment with just the relevant part. I understand your POV. I can't derive it explicitly you are right. But as said if the returned object could cause some issue in concurrency env I would expect some warning in the javadoc about the return part. Having a stateful predicate that besides is not documented as such would be both an error and a lack in terms of javadoc. – davidxxx Jul 16 '19 at 12:31
0

Matcher does not have the method asPredicate; it's Pattern that does. As such the returned Predicate is thread safe too - it will return as new Matcher that the Predicate will be build from - because the documentation says it is immutable.

Eugene
  • 117,005
  • 15
  • 201
  • 306