来自带有 next() 和 get() 的对象的迭代器
Iterator from object with next() and get()
给定这样一个对象:
Matcher matcher = pattern.matcher(sql);
像这样使用:
Set<String> matches = new HashSet<>();
while (matcher.find()) {
matches.add(matcher.group());
}
我想用更面向对象的东西替换这个 while 循环:
new Iterator<String>() {
@Override
public boolean hasNext() {
return matcher.find();
}
@Override
public String next() {
return matcher.group();
}
}
这样我就可以很容易地,例如制作匹配流,坚持使用流畅的 API 等。
问题是,我不知道也找不到更简洁的方法来创建此 Stream 或 Iterator。像上面这样的匿名 class 对我来说太冗长了。
我曾希望在 jdk 中找到 IteratorFactory.from(matcher::find, matcher::group)
或 StreamSupport.of(matcher::find, matcher::group)
之类的东西,但到目前为止还没有成功。我毫不怀疑像 apache commons 或 guava 这样的库为此提供了一些东西,但假设我不能使用它们。
在 jdk 中是否有方便的流或迭代器工厂采用 hasNext/next 方法组合?
在 java-9 中,您可以通过以下方式完成:
Set<String> result = matcher.results()
.map(MatchResult::group)
.collect(Collectors.toSet());
System.out.println(result);
在 java-8 中你需要一个后端口,取自
编辑
顺便说一句,有一种方法 tryAdvance
可以合并 find/group
,像这样:
static class MyIterator extends AbstractSpliterator<String> {
private Matcher matcher;
public MyIterator(Matcher matcher) {
// I can't think of a better way to estimate the size here
// may be you can figure a better one here
super(matcher.regionEnd() - matcher.regionStart(), 0);
this.matcher = matcher;
}
@Override
public boolean tryAdvance(Consumer<? super String> action) {
while (matcher.find()) {
action.accept(matcher.group());
return true;
}
return false;
}
}
用法举例:
Pattern p = Pattern.compile("\d");
Matcher m = p.matcher("12345");
Set<String> result = StreamSupport.stream(new MyIterator(m), false)
.collect(Collectors.toSet());
我写的这个class体现了我想在jdk中找到的东西。显然它只是不存在。 提供了 java 9 流解决方案。
public static class SearchingIterator<T> implements Iterator<T> {
private final BooleanSupplier advancer;
private final Supplier<T> getter;
private Optional<T> next;
public SearchingIterator(BooleanSupplier advancer, Supplier<T> getter) {
this.advancer = advancer;
this.getter = getter;
search();
}
private void search() {
boolean hasNext = advancer.getAsBoolean();
next = hasNext ? Optional.of(getter.get()) : Optional.empty();
}
@Override
public boolean hasNext() {
return next.isPresent();
}
@Override
public T next() {
T current = next.orElseThrow(IllegalStateException::new);
search();
return current;
}
}
用法:
Matcher matcher = Pattern.compile("\d").matcher("123");
Iterator<String> it = new SearchingIterator<>(matcher::find, matcher::group);
给定这样一个对象:
Matcher matcher = pattern.matcher(sql);
像这样使用:
Set<String> matches = new HashSet<>();
while (matcher.find()) {
matches.add(matcher.group());
}
我想用更面向对象的东西替换这个 while 循环:
new Iterator<String>() {
@Override
public boolean hasNext() {
return matcher.find();
}
@Override
public String next() {
return matcher.group();
}
}
这样我就可以很容易地,例如制作匹配流,坚持使用流畅的 API 等。
问题是,我不知道也找不到更简洁的方法来创建此 Stream 或 Iterator。像上面这样的匿名 class 对我来说太冗长了。
我曾希望在 jdk 中找到 IteratorFactory.from(matcher::find, matcher::group)
或 StreamSupport.of(matcher::find, matcher::group)
之类的东西,但到目前为止还没有成功。我毫不怀疑像 apache commons 或 guava 这样的库为此提供了一些东西,但假设我不能使用它们。
在 jdk 中是否有方便的流或迭代器工厂采用 hasNext/next 方法组合?
在 java-9 中,您可以通过以下方式完成:
Set<String> result = matcher.results()
.map(MatchResult::group)
.collect(Collectors.toSet());
System.out.println(result);
在 java-8 中你需要一个后端口,取自
编辑
顺便说一句,有一种方法 tryAdvance
可以合并 find/group
,像这样:
static class MyIterator extends AbstractSpliterator<String> {
private Matcher matcher;
public MyIterator(Matcher matcher) {
// I can't think of a better way to estimate the size here
// may be you can figure a better one here
super(matcher.regionEnd() - matcher.regionStart(), 0);
this.matcher = matcher;
}
@Override
public boolean tryAdvance(Consumer<? super String> action) {
while (matcher.find()) {
action.accept(matcher.group());
return true;
}
return false;
}
}
用法举例:
Pattern p = Pattern.compile("\d");
Matcher m = p.matcher("12345");
Set<String> result = StreamSupport.stream(new MyIterator(m), false)
.collect(Collectors.toSet());
我写的这个class体现了我想在jdk中找到的东西。显然它只是不存在。
public static class SearchingIterator<T> implements Iterator<T> {
private final BooleanSupplier advancer;
private final Supplier<T> getter;
private Optional<T> next;
public SearchingIterator(BooleanSupplier advancer, Supplier<T> getter) {
this.advancer = advancer;
this.getter = getter;
search();
}
private void search() {
boolean hasNext = advancer.getAsBoolean();
next = hasNext ? Optional.of(getter.get()) : Optional.empty();
}
@Override
public boolean hasNext() {
return next.isPresent();
}
@Override
public T next() {
T current = next.orElseThrow(IllegalStateException::new);
search();
return current;
}
}
用法:
Matcher matcher = Pattern.compile("\d").matcher("123");
Iterator<String> it = new SearchingIterator<>(matcher::find, matcher::group);