Java8_Lambda表达式进阶(比较器)

我们先来看两个题

  1. 计算一个字符串中小写字母个数

    计算个数我们知道可以用count方法,然后剩下就是找到字符串中的小写字母,使用String对象的chars方法可以拿到字符列表,然后过滤小写字母

    public static int countLowercaseLetters(String string) {
    return (int) string.chars()
                     .filter(Character::isLowerCase)
                       .count();
    }
    
  1. 在一个字符串列表中,找出包含最多小写字母的字符串,对于空列表,返回Optional<String> 对象

    这里我们接收的是一个字符串列表,要输出的是一个Optional,这里还要找的是最多,看到最多我们可以想到用max方法,max接收的是一个比较器,可以用来比较大小

    public class Main {
    
        public static void main(String[] args) {
            List<String> strings = Arrays.asList("Hello world","hello","welcome");
            mostLowercaseString(strings).ifPresent(System.out::println);//Hello world
        }
    
        public static int countLowercaseLetters(String string) {
            return (int)string.chars().filter(Character::isLowerCase).count();
        }
    
        public static Optional<String> mostLowercaseString(List<String> strings) {
            return strings.stream().max(Comparator.comparingInt(Main::countLowercaseLetters));
        }
    }
    
    

这里我们主要来分析第二个问题,重点看这里

strings.stream().max(Comparator.comparingInt(Main::countLowercaseLetters));

max函数接收的是一个Compartor比较器,返回一个Optional

Optional<T> max(Comparator<? super T> comparator);

Comparator我们在Java8之前就已经很熟悉了,以前我们会这样来生成一个Compartor

new Comparator<String>() {
            @Override
            public int compare(String s1, String s2) {
                return countLowercaseLetters(s1) - countLowercaseLetters(s2);
            }
        }

在Java8中,Compartor已经变成了一个函数式接口,并且封装了很多常用的默认方法

@FunctionalInterface
public interface Comparator<T> 

所以刚才的代码我们可以写成下面这种Labmda表达式的形式

(s1,s2)->countLowercaseLetters(s1)-countLowercaseLetters(s2)

这种最常用的比较两个数字大小的Compartor内部也封装了默认方法,叫做comparingInt

public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) {
    Objects.requireNonNull(keyExtractor);
    return (Comparator<T> & Serializable)
        (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2));
}

可以看到其内部实现

(c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2));

就是我们上面(s1,s2)->countLowercaseLetters(s1)-countLowercaseLetters(s2)这种Lambda表达式,只不过它封装到comparingInt方法中,对外调用更加方便

它内部Lambda表达式右边具体的实现是这样写的

Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2));

这里有个keyExtractor,这个ToIntFunction<? super T> 作为方法参数传递进来的,是一个Lambda表达式

@FunctionalInterface
public interface ToIntFunction<T> {

    /**
     * Applies this function to the given argument.
     *
     * @param value the function argument
     * @return the function result
     */
    int applyAsInt(T value);
}

这个函数式接口接收一个值,返回一个数字,也就是说comparingInt方法将这种行为作为参数传递进来,方法内部只进行Integer.compare比较,具体比较的数字是多少,是交给传进来的Lambda表达式来描述这个行为的,所以我们用comparingInt方法来实现就可以这样写:

strings.stream().max(Comparator.comparingInt(item -> countLowercaseLetters(item)));

item -> countLowercaseLetters(item)这个Lambda表达式正好符合方法引用的规则,所以可以简写成

strings.stream().max(Comparator.comparingInt(Main::countLowercaseLetters));

总结

Lambda表达式在流的使用中是很常见的一种操作,其中比较器也是很常用的一种操作,熟练使用其内部封装好的默认方法有助于我们提高效率。

    原文作者:大鹏_xzlp
    原文地址: https://www.jianshu.com/p/8f3efbd6f18e
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞