What is benefit in design of java.util.regex.Pattern and java.util.regex.Matcher?

It seems to been java.util.regex.Pattern and java.util.regex.Matcher are aggregation relationship, I think. And java API said that use them below.

Pattern p = Pattern.compile("a*b");
Matcher m = p.matcher("aaaaab");
boolean b = m.matches();

Why Pattern and Matcher are initialize through static method? What is benefit placing such a possibility? Has it disadvantage call creator on my source directly?

Answer

Why Pattern is created by static factory method?

As per documentation of Pattern,

A (Pattern) is compiled representation of a regular expression.

A Pattern object will be associated with a pattern, and users of this objects are supposed to create it once and use it many times. By providing a static factory, Pattern class has freedom to perform internal checks before returning the Pattern object. For example, it can (if it wishes to) cache the Pattern instances and return the cached instance if same pattern string is provided in another call to compile (Note: This is not the way it is implemented though, however, it has that freedom due to use of static factory).

Why Matcher is created through factory method on Pattern?

Matcher can be used for two purposes
(Below is simplified perspective for sake of discussion, refer Java doc of Matcher for more details):

  1. Check whether given string matches a given regex.
  2. Match the given string against a given pattern, and return various match results.

For the first case, one can use Pattern.matches(regex, string) form of method invocation. In this case, the regex will be compiled and a boolean result will be returned after the match. Note that this is sort of a functional style of programming – and it works fine here because there are no matching state to be maintained.

For the second case, a match state has to be maintained which user can query after the matching is performed. Hence, in this case Matcher object is used which can maintain state of match results. Since, Matcher object cannot exist without a corresponding Pattern object, the API developer allows its creation only through an instance of Pattern – thus users to invoke p.matcher('aaaaab'). Internally, the code in Pattern class looks like below:

public Matcher matcher(CharSequence input) {
    if (!compiled) {
        synchronized(this) {
            if (!compiled)
                compile();
        }
    }
    Matcher m = new Matcher(this, input);
    return m;
}

As can be seen, Matcher takes Pattern as constructor parameter – so that it can invoke it at various points to get & maintain match result

PS
Like any API, the Pattern and Matcher could have been implemented bit differently as well – not all Java APIs are consistent in their design – I guess there is always some trait of the developer who developed those APIs left behind. Above answer is my interpretation of what approach those developers took.

Leave a Reply

Your email address will not be published. Required fields are marked *