选项1:筛选
你可以编写一个有状态的筛选器,但是你绝不能这样做,因为它违反了filter(Predicate<? super T> predicate)
的契约:
predicate
- 应用于每个元素以确定是否应包括它的非干扰性、无状态谓词
public class NoRepeatFilter<T> implements Predicate<T> {
private T prevValue;
@Override
public boolean test(T value) {
if (value.equals(this.prevValue))
return false;
this.prevValue = value;
return true;
}
}
测试
List<String> result = Stream
.of("A", "A", "A", "B", "B", "A", "A", "A", "C", "C", "C", "A", "A", "B", "B", "A")
// .parallel()
.filter(new NoRepeatFilter<>())
.collect(Collectors.toList());
System.out.println(result);
输出
[A, B, A, C, A, B, A]
它必须是无状态的原因是,如果流是并行的,例如取消注释 .parallel()
后再次运行测试,则会失败:
[A, A, B, B, A, C, C, C, A, B, B, A]
选项2:收集器
一种有效的解决方案是使用 Collector
创建自己的收集器,使用 of(...)
:
public class NoRepeatCollector {
public static <E> Collector<E, ?, List<E>> get() {
return Collector.of(ArrayList::new,
NoRepeatCollector::addNoRepeat,
NoRepeatCollector::combineNoRepeat);
}
private static <E> void addNoRepeat(List<E> list, E value) {
if (list.isEmpty() || ! list.get(list.size() - 1).equals(value))
list.add(value);
}
private static <E> List<E> combineNoRepeat(List<E> left, List<E> right) {
if (left.isEmpty())
return right;
if (! right.isEmpty())
left.addAll(left.get(left.size() - 1).equals(right.get(0))
? right.subList(1, right.size()) : right);
return left;
}
}
测试
List<String> result = Stream
.of("A", "A", "A", "B", "B", "A", "A", "A", "C", "C", "C", "A", "A", "B", "B", "A")
// .parallel()
.collect(NoRepeatCollector.get());
System.out.println(result);
输出结果(使用和不使用.parallel()
)
[A, B, A, C, A, B, A]
选项3:循环
如果您的输入是List
(或其他Iterable
),您可以使用简单的循环删除重复值:
public static <E> void removeRepeats(Iterable<E> iterable) {
E prevValue = null;
for (Iterator<E> iter = iterable.iterator(); iter.hasNext(); ) {
E value = iter.next();
if (value.equals(prevValue))
iter.remove();
else
prevValue = value;
}
}
测试
List<String> list = new ArrayList<>(Arrays.asList(
"A", "A", "A", "B", "B", "A", "A", "A", "C", "C", "C", "A", "A", "B", "B", "A"));
removeRepeats(list);
System.out.println(list);
Output
[A, B, A, C, A, B, A]
Collector
,这样重复的元素就可以在添加到结果List
时被移除。更好的选择是不要使用流。 - AndreasSet
并解决它。 :) - Stefan Haberl