JDK中是否存在支持hasNext/next组合的便捷Iterator或Stream工厂?
Great question! Unfortunately, the JDK doesn't include a built-in factory method that directly takes separate hasNext and next suppliers to create an Iterator or Stream—which is a bit surprising given how common this use case is with Matcher. But don't worry, there are clean, JDK-only ways to avoid that verbose anonymous class.
1. Wrap a tiny custom utility class (cleanest approach)
Since you can't use third-party libraries, write a simple reusable utility to encapsulate the anonymous Iterator logic. This is one-time code and makes your main code much cleaner:
// Put this in a utility class in your project public class IteratorFactories { public static <T> Iterator<T> from(BooleanSupplier hasNext, Supplier<T> next) { return new Iterator<>() { @Override public boolean hasNext() { return hasNext.getAsBoolean(); } @Override public T next() { return next.get(); } }; } }
Now you can create your Iterator and Stream in concise lines:
Iterator<String> matchIterator = IteratorFactories.from(matcher::find, matcher::group); Stream<String> matchStream = StreamSupport.stream( Spliterators.spliteratorUnknownSize(matchIterator, Spliterator.ORDERED), false // sequential stream; set to true for parallel if needed );
2. Use Stream.iterate (Java 9+)
If you're on Java 9 or later, you can leverage the overload of Stream.iterate that takes a predicate to terminate the stream. It's a slight hack since we use a dummy initial value, but it avoids writing any custom classes:
Stream<String> matchStream = Stream.iterate( null, // Dummy initial value ignored -> matcher.find(), // Terminate when find() returns false ignored -> matcher.group() // Get the match for each iteration ) .skip(1); // Skip the dummy initial null value
3. Direct Spliterator creation (no utility class, minimal boilerplate)
If you don't want to add a utility class, you can wrap the anonymous Iterator directly into a Spliterator to get a Stream—though this doesn't save much code over your original approach, it's still fully JDK-native:
Spliterator<String> spliterator = Spliterators.spliteratorUnknownSize( new Iterator<>() { @Override public boolean hasNext() { return matcher.find(); } @Override public String next() { return matcher.group(); } }, Spliterators.ORDERED | Spliterators.NONNULL ); Stream<String> matchStream = StreamSupport.stream(spliterator, false);
Why no built-in JDK factory?
The core reason is that Iterator has two abstract methods (hasNext and next), so it's not a functional interface—you can't construct it with a single lambda. The JDK hasn't added a dedicated factory for this specific combination of suppliers, which is why third-party libraries like Guava have their own versions (but you can't use those here). Your custom utility class fills that gap perfectly, and it's trivial to maintain.
内容的提问来源于stack exchange,提问作者Marnes

