0%

Java基础—Lambda表达式与方法引用

这一部分主要记录了Java中Lambda表达式的使用方式和方法引用。Lambda表达式是函数式编程思想的体现,函数式编程思想尽量忽略面向对象的复杂语法:“强调做什么,而不是以什么形式去做”。Lambda表达式遵循“可推导就是可省略”的原则,无需指定参数类型,也无需指定的重载形式,它们都将被自动推导。

方法引用是Lambda的孪生兄弟,与Lambda表达式同样可以根据上下文进行推导,使用方法引用可以减少代码复杂度。

文章结构分为「Lambda表达式的格式与使用、Lambda表达式与匿名内部类的区别、方法引用概述、Lambda表达式支持的方法引用」四个部分。

Lambda表达式的格式与使用

使用前提

  • 必须要有接口,接口只有一个抽象方法
  • 必须有上下文环境才能推到Lambda对应的接口

Lambda表达式的标准格式

格式
标准格式由三要素组成:形式参数箭头代码块

1
(形式参数) -> {代码块(具体要做的事情)}

示例

示例要求:计算x + y,使用有参有返回的抽象方法

代码实现:

接口类

1
2
3
public interface Addable {
int add(int x,int y);
}

主类

1
2
3
4
5
6
7
8
9
10
11
12
public class AddableDemo {
public static void main(String[] args) {
useAddable((int x, int y) -> {
return x + y;
});
}

private static void useAddable(Addable a) {
int sum = a.add(10, 20);
System.out.println(sum);
}
}

说明

useAddable(Addable a)需要传入一个Addable接口的实现类。传入后,useAddable(Addable a)方法就可以调用Addable接口中的a.add(int x, int y)的方法。所以主类中我们就传入了一个Labmda表达式,相当于重写了接口类的 add(int x,int y)方法。

此处也可以使用匿名内部类重写a.add(int x, int y)来实现,但较为麻烦,具体实现如下:

1
2
3
4
5
6
useAddable(new Addable() {
@Override
public int add(int x, int y) {
return x + y;
}
});

Lambda表达式的缩略形式

格式

Lambda表达式可以有条件的缩略,具体缩略情况如下:

  1. 省略参数类型
  2. 省略小括号:参数只有一个
  3. 省略大括号和分号,以及return:如果只有一条语句

示例

用缩略写法表示上一个示例

1
useAddable((x, y) -> x + y);

Lambda表达式和匿名内部类的区别

  • 所需类型不同
    • 匿名内部类:可以是接口,也可以是抽象类,还可以是具体类
    • Lambda表达式:只能是接口
  • 使用限制不同
    • 如果接口抽象方法1个:都可以
    • 如果接口抽象方法多个匿名内部类only
  • 实现原理不同
    • 匿名内部类:编译之后,产生一个单独的.class字节码文件
    • Lambda表达式:编译之后,没有一个单独的.class字节码文件。对应的字节码会在运行的时候动态生成

方法引用概述

方法引用符

1
::

推导与省略

  • 如果使用Lambda,那么根据“可推导就是可省略”的原则,无需指定参数类型也无需指定的重载形式,它们都将被自动推导
  • 如果使用方法引用,也是同样可以根据上下文进行推导
  • 方法引用是Lambda的孪生兄弟

示例:

1
2
3
4
5
6
7
8
9
public class PrintableDemo {
public static void main(String[] args) {
usePrintable(System.out::println);//方法引用
}

private static void usePrintable(Printable p){
p.printInt(46);
}
}

Lambda表达式支持的方法引用

支持如下方法的方法引用:

  • 引用类方法
  • 引用对象实例方法
  • 引用类的实例方法
  • 引用构造器

引用类方法

格式

类名::静态方法
范例

Integer::parseInt

其调用的方法是:public static int parseInt(String s)

示例

练习:

  1. 定义一个接口(Converter),里面定义一个抽象方法:int convert(String s);
  2. 定义一个测试类(ConverterDemo),在测试类中提供两个方法
    一个方法是:useConverter(Converter c)
    一个方法是主方法,在主方法中调用useConverter方法
1
2
3
4
5
6
7
8
9
10
11
12
public class ConverterDemo {
public static void main(String[] args) {
// useConverter((String s) -> {
// return Integer.parseInt(s);
// });
useConverter(Integer::parseInt);
}
//Lambda表达式被类方法替代的时候,它的形式参数全部传递给静态方法作为参数
private static void useConverter(Converter c){
c.convert("666");
}
}

引用对象实例方法

格式

对象::成员方法

范例

"HelloWorld"::toUpperCase String

类中的方法:public String toUpperCase() 将此String所有字符转换为大写

传参

Lambda表达式被对象的实例方法替代的时候,它的形式参数全部传递给该方法作为参数

示例

1
2
3
4
5
6
7
8
9
10
public class PrinterDemo {
public static void main(String[] args) {
PrintString ps = new PrintString();//类
usePrinter(ps::printUpper);//的实例方法
}

private static void usePrinter(Printer p){
p.printUpperCase("hfd");
}
}

引用类的实例放法

引用类的实例方法,其实就是引用类中的成员方法

格式

类名::成员方法

范例

String::substring

使用的public String substring(int beginIndex,int endIndex)

(从beginIndex开始到endIndex结束,截取字符串。返回一个子串,子串的长度为endIndex-beginIndex)

传参

Lambda表达式被类的实例方法替代的时候,第一个参数作为调用者后面的参数全部传递给该方法作为参数

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class MyStringDemo {
public static void main(String[] args) {
//Lambda
useMyString((String s, int x, int y) -> s.substring(x, y));

//引用类的实例方法
useMyString(String::substring);

//Lambda表达式被类的实例方法替代的时候
//第一个参数作为调用者
//后面的参数全部传递给该方法作为参数
}

private static void useMyString(MyString my){
System.out.println(my.mySubString("abcdefg", 2, 5));;
}
}

引用构造器(构造方法)

格式

类名::new
范例

Student::new

传参

Lambda表达式被构造器替代的时候,它的形式参数全部传递给构造器作为参数

示例
练习

  1. 定义一个类(Student),里面有两个成员变量(name,age) 并提供无参构造方法和带参构造方法,以及成员变量对应的get和set方法

  2. 定义一个接口(StudentBuilder),里面定义一个抽象方法**Student build(String name,int age);**

  3. 定义一个测试类(StudentDemo),在测试类中提供两个方法

    一个方法是:useStudentBuilder(StudentBuilder s)

    一个方法是主方法,在主方法中调用useStudentBuilder方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class StudentDemo {
public static void main(String[] args) {

//Lambda表达式标准写法:
// useStudentBuilder((String name, int age) -> {
//// Student s = new Student(name, age);
//// return s;
// return new Student(name, age);
// });


useStudentBuilder((String name, int age) -> new Student(name, age));//Lambda表达式缩略

useStudentBuilder(Student::new);//引用构造器方法

//Lambda表达式被构造器替代的时候,它的形式参数全部传递给构造器作为参数
}

private static void useStudentBuilder(StudentBuilder sb){
Student s = sb.build("王守义", 13);
System.out.println(s.toString());
}
}