# How to Perform a Java Regular Expression Match in Spring Boot

> Learn the proper method for performing a Java regular expression match in Spring Boot. Use Pattern compile and Matcher methods matches() or find() for efficient validation.

- Repository: [Spring/spring-boot](https://github.com/spring-projects/spring-boot)
- Tags: how-to-guide
- Published: 2026-02-12

---

**The proper method for performing a Java regular expression match in Spring Boot follows the standard JDK pattern: compile a `Pattern` once with `Pattern.compile()`, create a `Matcher` for the input string, and invoke `matches()` for a full-string validation or `find()` for a partial search.**

Spring Boot does not introduce its own regex abstraction; instead, the framework relies on the immutable, thread-safe `java.util.regex` API for all validation logic. According to the spring-projects/spring-boot source code, the compile-once, match-many idiom appears consistently across endpoint validation, cookie handling, and property verification modules.

## The Standard Pattern: Compile Once, Match Many

The foundation of any Java regular expression match begins with `Pattern.compile(String)`. This method parses the regex string into an immutable `Pattern` object that can be safely shared across multiple threads and method invocations. In `org.springframework.boot.actuate.endpoint.EndpointId`, the Spring Boot team stores compiled patterns as `static final` constants to eliminate the computational overhead of recompilation during runtime.

The canonical workflow follows three distinct steps:

1. **Compile** the regex with `Pattern.compile(String regex, int flags)` (optional flags such as `Pattern.CASE_INSENSITIVE`).
2. **Create a Matcher** by calling `pattern.matcher(CharSequence input)`.
3. **Execute** the match using either `matches()` for a full string match or `find()` to locate substrings.

## Full Match vs. Partial Match

Understanding the distinction between anchoring patterns determines which method you invoke on the `Matcher` instance.

### Using matches() for Entire String Validation

The `matches()` method attempts to match the entire input sequence against the pattern. This approach is required when validating that a complete string conforms to a specific format, such as an endpoint ID or IP address. In [`EndpointId.java`](https://github.com/spring-projects/spring-boot/blob/main/EndpointId.java) at line 58, the constructor validates the input by asserting that the supplied value satisfies the compiled pattern:

```java
// From module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EndpointId.java#L58
private static final Pattern VALID_PATTERN = Pattern.compile("[a-zA-Z0-9.-]+");

public EndpointId(String value) {
    Assert.isTrue(VALID_PATTERN.matcher(value).matches(),
                  "'value' must only contain valid chars");
    this.value = value;
}

```

### Using find() for Substring Searching

When you need to determine if a pattern exists anywhere within the input text rather than matching the whole string, use `find()`. While Spring Boot's internal validation typically requires full matches via `matches()`, substring searches would use `find()` to locate partial occurrences within larger character sequences.

## Real-World Examples from Spring Boot

The Spring Boot codebase demonstrates consistent regex practices across multiple modules. These examples illustrate the proper method for performing a Java regular expression match in production contexts.

### EndpointId Validation

In [`module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EndpointId.java`](https://github.com/spring-projects/spring-boot/blob/main/module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EndpointId.java), the framework validates that endpoint identifiers contain only permitted alphanumeric characters, dots, and hyphens. The implementation stores the pattern as a constant and invokes `matches()` to ensure the entire identifier conforms to the specification.

```java
public class EndpointId {
    private static final Pattern VALID_PATTERN = Pattern.compile("[a-zA-Z0-9.-]+");
    private final String value;

    public EndpointId(String value) {
        Assert.isTrue(VALID_PATTERN.matcher(value).matches(),
                      "'value' must only contain valid chars");
        this.value = value;
    }
}

```

### Cookie SameSite Policy Matching

The `CookieSameSiteSupplier` class in [`module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/CookieSameSiteSupplier.java`](https://github.com/spring-projects/spring-boot/blob/main/module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/CookieSameSiteSupplier.java) (line 98) uses regex matching to determine cookie name patterns. The supplier compiles the regex during construction and tests cookie names using `matches()` to decide whether to apply strict SameSite policies.

```java
public class CookieSameSiteSupplier {
    private final Pattern pattern;

    private CookieSameSiteSupplier(String regex) {
        this.pattern = Pattern.compile(regex);
    }

    public SameSite getSameSite(Cookie cookie) {
        // Full match on cookie name
        if (pattern.matcher(cookie.getName()).matches()) {
            return SameSite.STRICT;
        }
        return SameSite.LAX;
    }
}

```

### Configuration Property Validation

Property validation in Spring Boot smoke tests demonstrates IP address verification using regex. The `SamplePropertiesValidator` in [`smoke-test/spring-boot-smoke-test-property-validation/src/main/java/smoketest/propertyvalidation/SamplePropertiesValidator.java`](https://github.com/spring-projects/spring-boot/blob/main/smoke-test/spring-boot-smoke-test-property-validation/src/main/java/smoketest/propertyvalidation/SamplePropertiesValidator.java) (line 27) compiles an IP pattern and validates host properties by calling `matches()` on the Matcher instance.

```java
public class SamplePropertiesValidator {
    private static final Pattern IP_PATTERN =
            Pattern.compile("^(?:[0-9]{1,3}\\.){3}[0-9]{1,3}$");

    public void validate(SampleProperties properties) {
        if (properties.getHost() != null &&
            !IP_PATTERN.matcher(properties.getHost()).matches()) {
            throw new IllegalArgumentException("Invalid host IP");
        }
    }
}

```

## Performance and Thread Safety Considerations

`Pattern` objects are immutable and inherently thread-safe, making them ideal candidates for `static final` constants in Spring components. By compiling the regex during class loading rather than during method execution, you avoid the expensive cost of parsing the regex string repeatedly. The `Matcher` instance, however, is not thread-safe and should be created fresh for each validation call, or alternatively, use `ThreadLocal<Matcher>` for high-throughput scenarios to prevent object churn.

## Summary

- **Compile once**: Store `Pattern` objects as `static final` constants to avoid recompilation overhead, as implemented in [`EndpointId.java`](https://github.com/spring-projects/spring-boot/blob/main/EndpointId.java).
- **Full match validation**: Use `matcher(input).matches()` when the entire string must conform to the pattern, following the pattern established in [`CookieSameSiteSupplier.java`](https://github.com/spring-projects/spring-boot/blob/main/CookieSameSiteSupplier.java).
- **Partial match search**: Use `matcher(input).find()` when searching for substrings within larger text bodies.
- **Thread safety**: `Pattern` is thread-safe and reusable across threads; `Matcher` is not thread-safe and should be instantiated per usage or managed via `ThreadLocal`.

## Frequently Asked Questions

### Should I compile the Pattern every time I need to validate a string?

No. According to the Spring Boot source code in [`EndpointId.java`](https://github.com/spring-projects/spring-boot/blob/main/EndpointId.java), you should compile the `Pattern` once as a `static final` constant. `Pattern` objects are immutable and thread-safe, so reusing a single compiled instance eliminates redundant parsing overhead and improves application performance significantly.

### What is the difference between matches() and find() in Java regex?

The `matches()` method attempts to match the entire input sequence against the pattern, requiring the regex to account for the full string from start to end. The `find()` method scans the input to locate the next subsequence that matches the pattern, allowing for partial matches within larger text. Spring Boot validation typically uses `matches()` for complete string validation as seen in [`SamplePropertiesValidator.java`](https://github.com/spring-projects/spring-boot/blob/main/SamplePropertiesValidator.java).

### Is Matcher thread-safe in Java?

No, `Matcher` instances are not thread-safe. While the `Pattern` object used to create the matcher is immutable and thread-safe, each `Matcher` maintains state about the current match position. For concurrent environments, create a new `Matcher` for each thread or use `ThreadLocal<Matcher>` to avoid synchronization issues and race conditions.

### How does Spring Boot handle regex flags like CASE_INSENSITIVE?

Spring Boot follows standard JDK practices by passing flags as the second argument to `Pattern.compile()`. For example, `Pattern.compile("^[A-Z]+$", Pattern.CASE_INSENSITIVE)` creates a case-insensitive pattern. This compiled pattern can then be stored as a constant and reused across the application for consistent case-insensitive matching operations.