lambda表达式

lambda是一个代码段,以及必须传入代码的变量规范。主要用来简化代码。

引入

Array.sort(T[],Comparator) 方法举例,该方法接收一个泛型数组,以及一个该类型对应的比较器(Comparator接口)。
查看Comparator 接口的代码,其包含compare的抽象方法,如果需要创建自定义比较规则,则需要自定义一个类实现Comparator接口,然后实例化对象,并将这个对象传递给sort方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package lambda;

import java.util.Arrays;
import java.util.Comparator;

/**
 * @author louyy
 * @date Created on 2019/9/15
 */
public class Main {
    public static void main(String[] args) {
        String s[] = {"aa","b","ccc"};
        Arrays.sort(s,new MyComparator());
//        输出
        Arrays.stream(s).forEach(System.out::println);
    }
}

class MyComparator implements Comparator{
    @Override
    public int compare(String s, String t1) {
        return s.length() - t1.length();
    }
}

使用lambda之后,可以将MyComparator作为代码段直接丢入sort中:

1
2
3
4
5
6
7
8
public class Main {
    public static void main(String[] args) {
        String s[] = {"aa","b","ccc"};
        Arrays.sort(s,(s1,s2)-> s1.length() - s2.length());
//        输出
        Arrays.stream(s).forEach(System.out::println);
    }
}

lambda语法

lambda使Java支持函数式编程,主要格式为(/*参数列表*/)->{/*函数体*/}
如果函数体只有一行代码,可以省略花括号和return,但是上例在这么做了之后,IDEA提示我可以进一步简化:

简化之后:

Arrays.sort(s, Comparator.comparingInt(String::length));

使用了Comparator接口的静态方法comparingInt,看下源码:

1
2
3
4
5
6
static  Comparator comparingInt(ToIntFunction var0) {
    Objects.requireNonNull(var0);
    return (Comparator)((Serializable)((var1x, var2x) -> {
        return Integer.compare(var0.applyAsInt(var1x), var0.applyAsInt(var2x));
    }));
}

comparingInt的接受一个ToIntFunction类型的叫做var0的函数式接口,但是实际给出的是String::length.
String::length等价于s -> s.length()等价于s -> { return s.length() }
这样就整明白了,Comparator.comparingInt表示我要比较的是Int类型,但是给的是String类型,所以还需要一个类型转换器。
我需要比较字符串大小的话,就需要用到String的length,ToIntFunction就是定义这样的类型转换规则的接口,通过看他的源码可以发现:

1
2
3
4
5
6
package java.util.function;

@FunctionalInterface
public interface ToIntFunction {
    int applyAsInt(T var1);
}

它只有一个接口,把泛型转换为int类型,之后会说到这个是Java的函数式接口。所以这里就相当于我定义了这样的接口:

1
2
3
4
5
6
7
ToIntFunction var = new ToIntFunction(){
    @Override
    public int applyAsInt(String s) {
        return s.length();
    }
};
Arrays.sort(s, Comparator.comparingInt(var));

和简化的lambda对比
Arrays.sort(s, Comparator.comparingInt(String::length));
确实简化了不少。

关于comparingInt静态方法

再深入一点,上文comparingInt方法中,拿到的其实还是一个接口引用,只是后来在comparingInt里面,又通过lambda+调用接口引用(ToIntFunction)的applyAsInt方法+Integer.compare具体实现了。
但是这里我有有一个疑问,书里说Java根据lambda表达式所处方法的参数类型自动转换为对应的接口,但是如果lambda出现在普通代码中,如何确定类型?
在JDK源码中,我觉得是通过强制类型转换。

方法引用

一个例子:
Arrays.stream(s).forEach(System.out::println);

  • object::instanceMethod
  • Class::staticMethod
  • Class::instanceMethod

前两个类似这样:
System.out::println == x -> System.out.println(x)
第三种情况,第一个参数会成为方法的目标,余下的成为参数列表。
this::xxx super::xxx是合法的

构造器引用

Class::new

数组类型的构造器引用

int[]::new等同x -> new int[x]

你可能感兴趣的:(lambda表达式)