Predicate 怎么使用
-
如何上手,先看示例代码,filter入参接收一个 Predicate 对象,用于判断过滤集合中的元素
@Test public void test1() { List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); Predicate<Integer> predicate = integer -> integer % 2 == 0; List<Integer> collect = list.stream().filter(predicate).collect(Collectors.toList()); // List<Integer> collect = list.stream().filter(integer -> integer % 2 == 0).collect(Collectors.toList()); System.out.println(collect); } -
链路调用
-
多条件过滤
- && , ||
- and(), or()
- negate() 取反
@Test public void test2() { List<String> list = Arrays.asList("A", "AA", "AAA", "B", "BB", "BBB"); StringProcessor stringProcessor = new StringProcessor(); System.out.println(stringProcessor.filter( list, x -> x.startsWith("A"))); // [A, AA, AAA] System.out.println(stringProcessor.filter( list, x -> x.startsWith("A") && x.length() == 3)); // [AAA] Predicate<String> p1 = s -> s.startsWith("A"); System.out.println(stringProcessor.filter(list, p1.negate())); } class StringProcessor { List<String> filter(List<String> list, Predicate<String> predicate) { return list.stream().filter(predicate::test).collect(Collectors.toList()); } } // 链路调用 @Test public void test3(){ Predicate<String> startWithA = s -> s.startsWith("A"); boolean result = startWithA.or(x -> x.startsWith("m")).test("mkyong"); System.out.println(result); } -
与对象一起使用
public static List<Hosting> filterHosting(List<Hosting> hosting, Predicate<Hosting> predicate) { return hosting.stream() .filter(predicate) .collect(Collectors.toList()); } public static void main(String[] args) { Hosting h1 = new Hosting(1, "amazon", "aws.amazon.com"); Hosting h2 = new Hosting(2, "linode", "linode.com"); Hosting h3 = new Hosting(3, "liquidweb", "liquidweb.com"); Hosting h4 = new Hosting(4, "google", "google.com"); List<Hosting> list = Arrays.asList(new Hosting[]{h1, h2, h3, h4}); List<Hosting> result = HostingRespository.filterHosting(list, x -> x.getName().startsWith("g")); System.out.println("result : " + result); // google List<Hosting> result2 = HostingRespository.filterHosting(list, isDeveloperFriendly()); System.out.println("result2 : " + result2); // linode } public static Predicate<Hosting> isDeveloperFriendly() { return n -> n.getName().equals("linode"); }
Predicate 深入理解
-
常见的 Api上面已经介绍了几个,现在进一步通过源码来学习下 Predicate 提供的 Api
- and
- test,接收一个参数并返回布尔值
- or
- negate
@FunctionalInterface public interface Predicate<T> { /** * Evaluates this predicate on the given argument. * * @param t the input argument * @return {@code true} if the input argument matches the predicate, * otherwise {@code false} */ boolean test(T t); /** 与运算 * Returns a composed predicate that represents a short-circuiting logical * AND of this predicate and another. When evaluating the composed * predicate, if this predicate is {@code false}, then the {@code other} * predicate is not evaluated. * * <p>Any exceptions thrown during evaluation of either predicate are relayed * to the caller; if evaluation of this predicate throws an exception, the * {@code other} predicate will not be evaluated. * * @param other a predicate that will be logically-ANDed with this * predicate * @return a composed predicate that represents the short-circuiting logical * AND of this predicate and the {@code other} predicate * @throws NullPointerException if other is null */ default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); } /** 很好理解,取反 * Returns a predicate that represents the logical negation of this * predicate. * * @return a predicate that represents the logical negation of this * predicate */ default Predicate<T> negate() { return (t) -> !test(t); } /** 或运算 * Returns a composed predicate that represents a short-circuiting logical * OR of this predicate and another. When evaluating the composed * predicate, if this predicate is {@code true}, then the {@code other} * predicate is not evaluated. * * <p>Any exceptions thrown during evaluation of either predicate are relayed * to the caller; if evaluation of this predicate throws an exception, the * {@code other} predicate will not be evaluated. * * @param other a predicate that will be logically-ORed with this * predicate * @return a composed predicate that represents the short-circuiting logical * OR of this predicate and the {@code other} predicate * @throws NullPointerException if other is null */ default Predicate<T> or(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) || other.test(t); } /** * Returns a predicate that tests if two arguments are equal according * to {@link Objects#equals(Object, Object)}. * * @param <T> the type of arguments to the predicate * @param targetRef the object reference with which to compare for equality, * which may be {@code null} * @return a predicate that tests if two arguments are equal according * to {@link Objects#equals(Object, Object)} */ static <T> Predicate<T> isEqual(Object targetRef) { return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object); } }
BiPredicate 怎么使用
-
它比起 predicate 多了一个参数,可以联系 function 和 bifuncation 的关系
public interface BiPredicate<T, U> { boolean test(T t, U u); } -
还是先看示例代码
@Test public void test4() { BiPredicate<String, Integer> filter = (x, y) -> x.length() == y; ; boolean result = filter.test("mkyong", 6); System.out.println(result); // true boolean result2 = filter.test("java", 10); System.out.println(result2); // false } @Test public void testBiPredicate() { List<Domain> domains = Arrays.asList(new Domain("google.com", 1), new Domain("i-am-spammer.com", 10), new Domain("mkyong.com", 0), new Domain("microsoft.com", 2)); BiPredicate<String, Integer> bi = (domain, score) -> { return (domain.equalsIgnoreCase("google.com") || score == 0); }; System.out.println(filterBadDomain(domains, bi)); // [PredicateTest.Domain(name=google.com, score=1), PredicateTest.Domain(name=mkyong.com, score=0)] List<Domain> result4 = filterBadDomain(domains, bi.or( (name, score) -> name.equalsIgnoreCase("microsoft.com") && score>2) ); System.out.println(result4); } public static <T extends Domain> List<T> filterBadDomain(List<T> list, BiPredicate<String, Integer> biPredicate) { return list.stream() .filter(x -> biPredicate.test(x.getName(), x.getScore())) .collect(Collectors.toList()); } @Data class Domain { String name; Integer score; public Domain(String name, Integer score) { this.name = name; this.score = score; } } -
BiPredicate 的Api 跟 Predicate 没有太大差异,再此不在展开
参考