java8新特性-Lambda表达式

  1. 1. 一、Lambda表达式
    1. 1.1. 1.1 示例:
    2. 1.2. 1.2 推荐写法:
    3. 1.3. 1.3 总结:
  2. 2. 二、接口的默认方法
  3. 3. 三、函数式接口(Functional Interfaces)
    1. 3.1. 3.1 要求:
    2. 3.2. 3.2 示例:
    3. 3.3. 3.2 测试:
      1. 3.3.1. 测试结果:
    4. 3.4. 3.3 Function源码:
      1. 3.4.1. Interface Function<T,R>
    5. 3.5. 3.4 内置函数式接口—扩展:
  4. 4. 四、Optional
  5. 5. 五、方法引用
    1. 5.1. 5.1 通过静态方法引用来表示
      1. 5.1.1. 语法:
      2. 5.1.2. 案例:
    2. 5.2. 5.2 构造方法引用
      1. 5.2.1. 语法
      2. 5.2.2. 案例:

一、Lambda表达式

Lambda表达式是一种对接口实现的简洁写法

1.1 示例:

在老版本的 Java中是如何排列字符串的:

1
2
3
4
5
6
7
8
List<String> list = Arrays.asList("banana","apple", "sun","wall","applet");
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.compareTo(o1);
}
});
System.out.println(list);

输出:

[wall, sun, banana, applet, apple]

​ 只需要给静态方法Collections.sort传入一个 List 对象以及一个比较器来按指定顺序排列。通常做法都是创建一个匿名的比较器对象然后将其传递给 sort 方法。

Java 8提供了更简洁的语法,lambda表达式:

1
2
3
Collections.sort(list, (String o1, String o2)-> {
return o2.compareTo(o1);
});

显然,这样就不用再写传统的匿名对象的方式了,这样代码变得更简短。

这段代码我们还可以写得再简短些:

只有一条return语句,将花括号跟return去掉,如下

1
Collections.sort(list, (String o1, String o2)-> o2.compareTo(o1));

还可以再简短一点:

将数据类型string删掉。

1
Collections.sort(list, (o1, o2)-> o2.compareTo(o1));
因为List 类本身就有一个 sort方法。并且 Java编译器可以自动推导出参数类型,所以你可以不用再写一次类型。

1.2 推荐写法:

1
2
3
([名字1,名字N])->{
方法体
}

()和{}都不会省略,是为了提高可读性

只会省略参数类型

1.3 总结:

  • 如果方法体只有一行的情况,那么{}可以省略

    注意了如果该行是return语句,那么return关键字也必须省略

  • 如果方法只有一个参数的情况,那么()也可以省略

  • 对于方法的参数类型,要么全部省略要么全部不省略

二、接口的默认方法

Java 8使我们能够通过使用 default关键字向接口添加非抽象方法实现(含方法体的方法)。

重写抽象方法时可直接调用默认方法。

三、函数式接口(Functional Interfaces)

为了解决如何使现有的函数更友好的支持Lambda表达式的问题。

3.1 要求:

  • 接口只有一个抽象方法,但可以有多个非抽象方法;【这种接口一般称为函数式接口】

    可以在接口上添加@FunctionalInterface注解来做校验,大于一个抽象方法就会报错。

3.2 示例:

  1. 当使用多个抽象方法时(接口里的方法public abstract默认省略)

  1. 正确写法:

3.2 测试:

1
2
3
4
5
6
7
public static void main(String[] args) {
Function<String, Integer> convert = (String s)-> Integer.valueOf(s);

// 将数字字符串转换为整数类型
Integer converted = convert.apply("123");
System.out.println(converted.getClass());
}

测试结果:

3.3 Function源码:

Interface Function<T,R>

  • 参数类型

    T - 函数输入的类型

    R - 函数的结果类型

  • 表示接受一个参数并产生结果的函数。
  • R apply(T t)方法: 将Function对象应用到输入的参数上,然后返回计算结果。

3.4 内置函数式接口—扩展:

  1. Predicate 接口是只有一个参数的返回布尔类型值的 断言型 接口。
  2. Supplier 接口产生给定泛型类型的结果。 与 Function 接口不同,Supplier 接口不接受参数。
  3. Consumer 接口表示要对单个输入参数执行的操作。

四、Optional

Optional不是函数式接口,而是用于防止 NullPointerException 的工具。

Optional 是一个简单的容器,其值可能是null或者不是null。在Java 8中,你应该返回 Optional 而不是 null。

五、方法引用

可以通过 :: 关键字传递方法或构造函数的引用。

5.1 通过静态方法引用来表示

语法:

1
接口类型 名称 = 类名::static方法名

案例:

1
2
3
4
5
6
// Function<String, Integer> convert = (String s)-> Integer.valueOf(s);
Function<String, Integer> convert = Integer::valueOf;

// 将数字字符串转换为整数类型
Integer converted = convert.apply("123");
System.out.println(converted.getClass()); // class java.lang.Integer

5.2 构造方法引用

语法

1
接口类型 名称 = 类名::new;   //代表引用构造器,至于哪个构造器看接口方法的参数

案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class _03TestLambdaConstructorRef {

public static void main(String[] args) {

One one = Dog::new; // Dog::new 代表构造器[代表无参构造器]

Dog dog = one.test();//调用无参构造器

System.out.println(dog); // Dog [name=null, color=null]


Two two = Dog::new; // Dog::new 代表构造器[代表String name,String color构造器]
Dog otherDog = two.test("小狗", "黑色");

System.out.println(otherDog); // Dog [name=小狗, color=黑色]
}
}

class Dog{

private String name;
private String color;

public Dog(){

}

public Dog(String name, String color) {
this.name = name;
this.color = color;
}

@Override
public String toString() {
return "Dog [name=" + name + ", color=" + color + "]";
}
}


@FunctionalInterface
interface One{
Dog test(); //调用无参
}

@FunctionalInterface
interface Two{
Dog test(String name,String color); //调用有参
}