> 文章列表 > Java集合操作工具:some、any以及every

Java集合操作工具:some、any以及every

Java集合操作工具:some、any以及every

最近学习PAIP的时候,顺便看了下回味了下Common Lisp,注意到几个实用的集合操作函数,本文记录下在Java中的实现。

场景

我想大家在平常开发中应该经常遇到这样场景:想要从集合中找到符合某个条件元素,或者判断集合中是否存在某种数据,又或者是判断集合中的所有元素都符合某个要求。

针对第一种问题的基本写法是for-if-break:

Image thisImage;
for (Image image : list) {if (image.getId() == id) {thisImage = image;break;}
}
//继续使用thisImage

第二种也是类似:

boolean containsPNG = false;
for (Image image : list) {if (image.getType() == PNG) {containsPNG = true;break;}
}
//根据containsPNG进行下面操作

第三种则是:

boolean isAllPNG = true;
for (Image image : list) {if (image.getId() != PNG) {isAllPng = false;break;}
}
//根据isAllPNG进行下面操作

这几段都是简单代码,但是一个项目中可能出现多次,而且这三种情况代码非常相似,只有细节不同,但是表达的逻辑还是有很大区别,并不直白(要从代码中看出逻辑还是得花个5-10秒),没法一眼在3秒内得到代码意义。

正好Common Lisp规范中包含专门处理这类问题的标准函数,下面就来介绍下。

代码示例

首先是应对第一种情况的,我们想要找到集合中某个符合条件的元素,那么就有操作some

public void testSome() {List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);some(nums, this::isOdd).ifPresent(oddInt -> {//list中存在某个基数});some(images, image -> image.getId() == 0).ifPresent(invalidImage -> {//images中存在id为0的非法图片});
}private boolean isOdd(Integer i) {return i % 2 == 1;
}

处理第二种“是否包含任何符合某条件的元素”情况的操作是any

List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);boolean containsEvenNum = any(nums, i -> i % 2 == 0);//包含偶数
boolean containsPNG = any(images, image -> image.getType() == PNG);//图片列表中包含PNG
boolean notContainsNegativeNum = notAny(nums, i -> i < 0);//不包含任何负数

处理三种“是否所有元素都符合某个条件”情况的操作是every

List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);
List<String> strings = Arrays.asList("", "asdf", "1234");boolean allNonNull = every(strings, Objects::nonNull);//所有字符串都不是null
boolean allIsPositive = every(nums, i -> i > 0);//所有数字都是整数
boolean notAllStringIsDigits = notEvery(strings, TextUtils::isDigitsOnly);//不是所有的字符串都只有数字

工具实现

some实现如下:

public static <T> Optional<T> some(Iterable<T> iterable, Predicate<? super T> predicate) {if (iterable != null) {for (T t : iterable) {if (predicate.test(t)) {return Optional.of(t);}}}return Optional.empty();
}

这里的predicate是一个断言,用来检查数据是否符合要求,比如“是偶数”就是i -> i % 2 == 0,“正整数”就是i -> i > 0。返回值是Optional形式,详细用法见相关文档。

any的实现是:

public static <T> boolean any(Iterable<T> iterable, Predicate<? super T> predicate) {return some(iterable, predicate).isPresent();
}

因为“是否包含任何符合条件A的元素”相当于“存在某个符合条件A的元素”,所以直接用some来实现。相对的还有否定形式的notAny

public static <T> boolean notAny(Iterable<T> iterable, Predicate<? super T> predicate) {return !any(iterable, predicate);
}

every的实现是:

public static <T> boolean every(Iterable<T> iterable, Predicate<? super T> predicate) {return !some(iterable, t -> !predicate.test(t)).isPresent();
}

因为“所有元素都满足条件A”相当于“不符合条件A的元素不存在”,所以也可以用some来实现,相对应的否定形式为notEvery

public static <T> boolean notEvery(Iterable<T> iterable, Predicate<? super T> predicate) {return !every(iterable, predicate);
}