使用Java8新增的Predicate操作集合
Java 8 中 Collection集合新增了一些需要Predicate参数的方法,这些方法可以对集合元素进行过滤。程序可使用Lambda表达式构建Predicate对象。
描述:
Predicate< T>接口接受一个T类型参数,返回一个boolean值。该接口包含多种默认方法来将Predicate组合成其他复杂的逻辑(比如:与,或,非):
Predicate<String> predicate = (s) -> s.length() > 0;
predicate.test("foo"); // true
predicate.negate().test("foo"); // false
Predicate<Boolean> nonNull = Objects::nonNull;
Predicate<Boolean> isNull = Objects::isNull;
Predicate<String> isEmpty = String::isEmpty;
Predicate<String> isNotEmpty = isEmpty.negate();查看源码
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}查找对象
该代码完成了以下4个需求
统计书名中出现“疯狂”字符串的图书数量。
统计书名中出现“Java”字符串图书数量。
统计书名长度大于10的图书数量。
删除书名长度小于10的图书。
Predicate是一种谓词动作接口:是一个函数式接口,即表示一个动作
实现如下
import java.util.*;
import java.util.function.*;
public class PredicateTest {
public static void main(String[] args) {
// 创建books集合、为books集合添加元素的代码与前一个程序相同。
Collection books = new HashSet();
books.add(new String("轻量级Java EE企业应用实战"));
books.add(new String("疯狂Java讲义"));
books.add(new String("疯狂iOS讲义"));
books.add(new String("疯狂Ajax讲义"));
books.add(new String("疯狂Android讲义"));
// 统计书名包含“疯狂”子串的图书数量
System.out.println(calAll(books , ele->((String)ele).contains("疯狂")));
// 统计书名包含“Java”子串的图书数量
System.out.println(calAll(books , ele->((String)ele).contains("Java")));
// 统计书名字符串长度大于10的图书数量
System.out.println(calAll(books , ele->((String)ele).length() > 10));
// 使用Lambda表达式(目标类型是Predicate)过滤集合
books.removeIf(ele -> ((String)ele).length() < 10);
System.out.println(books);
}
public static int calAll(Collection books , Predicate p) {
int total = 0;
for (Object obj : books) {
// 使用Predicate的test()方法判断该对象是否满足Predicate指定的条件
if (p.test(obj)) {
total ++;
}
}
return total;
}
}运行结果
4 2 2 [疯狂Android讲义, 轻量级Java EE企业应用实战]
删除集合元素
Java 8 中 Collection集合中新增了一个removeIf(Predicate filter) 方法,该方法将会批量删除符合filter条件的所有元素。
方法:removeIf(Predicate<? super E> filter)
如上述代码中,删除书名长度小于10的图书 功能,这里追加一个 删除所有包含Java的元素
books.removeIf(o -> {
if (o.toString().contains("Java")){
return true;
}
return false;
});
// 以上代码简写
books.removeIf(o -> o.toString().contains("Java"));
books.forEach(System.out::println);运行结果
疯狂Ajax讲义 疯狂Android讲义 疯狂iOS讲义
组合谓词
Java 8定义了许多有用的java.util.function包中接口的组合接口,但这种组合并不都是一样的。所有的谓语的变体(《DoublePredicate,IntPredicate,LongPredicate和Predicate<T>)都定义了相同的组合与修改方法:and(),negate()和or()。但是Function<T>的基本数据类型变体就没有定义任何组合与修改方法。如果你拥有使用函数式编程语言的经验,那么你可能就发会发现这些不同之处和奇怪的忽略。
组合条件示例
Predicate<String> pred1 = name -> name.contains("Java");
Predicate<String> pred2 = name -> name.contains("IOS");
books.removeIf(pred1.or(pred2));源码分析
下边是JDK1.8.0_121中接口Collection的部分源码:
/**
* Removes all of the elements of this collection that satisfy the given
* predicate. Errors or runtime exceptions thrown during iteration or by
* the predicate are relayed to the caller.
*
* @implSpec
* The default implementation traverses all elements of the collection using
* its {@link #iterator}. Each matching element is removed using
* {@link Iterator#remove()}. If the collection's iterator does not
* support removal then an {@code UnsupportedOperationException} will be
* thrown on the first matching element.
*
* @param filter a predicate which returns {@code true} for elements to be
* removed
* @return {@code true} if any elements were removed
* @throws NullPointerException if the specified filter is null
* @throws UnsupportedOperationException if elements cannot be removed
* from this collection. Implementations may throw this exception if a
* matching element cannot be removed or if, in general, removal is not
* supported.
* @since 1.8
*/
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}下边是翻译后的源码(英语渣,如有错误,请指正):
/**
* 移除集合中满足给定条件的所有元素,错误或者运行时异常发生在迭代时或者把条件传递给调用者的时候。
*
* @implSpec
* 默认的实现贯穿了使用迭代器iterator的集合的所有元素。每一个匹配的元素都将被用Iterator接口中的
* remove()方法移除。如果集合的迭代器不支持移除,则在第一次匹配时就会抛出异常 UnsupportedOperationException
*
* @param filter 令元素移除成功的条件
* @return {@code true} 如果所有的元素都被移除
* @throws NullPointerException 如果有一个过滤器是空的
* @throws UnsupportedOperationException 如果元素不能被从该集合中移除。如果一个匹配元素不能被移除,
* 通常来说,它就不支持移除操作,这时可能抛出这个异常。
* @since 1.8
*/
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}未经允许请勿转载:程序喵 » Java函数式编程之Predicate 过滤操作
程序喵