Java8中的Lambda表达式 (2)

第一步:比如我们想要读取某个文件,那可以有如下方法:

public static String processFile() throws IOException { // Java7新增的语法,try(){},可自动关闭资源,减少了代码的臃肿 try( BufferedReader bufferedReader = new BufferedReader(new FileReader("D:\\JavaProject\\JavaBasicDemo\\test.txt"))){ return bufferedReader.readLine(); } }

可以看到,核心的行为动作就是 return bufferedReader.readLine();,表示读取第一行的数据并返回

那如果我们想要读取两行呢?三行?

第二步:这时就需要用到上面的函数式接口了,下面就是我们自己编写的函数式接口

@FunctionalInterface interface FileReadInterface{ // 这里接受一个BufferedReader对象,返回一个String对象 String process(BufferedReader reader) throws IOException; }

可以看到,只有一个抽象方法process() ,它就是用来处理第一步中的核心动作(读取文件内容)

至于想读取多少内容,那就需要我们在lambda表达式中定义了

第三步:接下来我们定义多个lambda表达式,用来传递函数式接口,其中每个lambda表达式就代表了一种不同的行为,代码如下:

// 读取一行 FileReadInterface fileReadInterface = reader -> reader.readLine(); // 读取两行 FileReadInterface fileReadInterface2 = reader -> reader.readLine() + reader.readLine();

第四步:我们需要修改第一步的processFile(),让其接受一个函数式接口,并调用其中的抽象方法,代码如下:

// 参数为第二步我们自己手写的函数式接口 public static String processFile(FileReadInterface fileReadInterface) throws IOException { try( BufferedReader bufferedReader = new BufferedReader(new FileReader("./test.txt"))){ // 这里我们不再自己定义行为,而是交给函数式接口的抽象方法来处理,然后通过lambda表达式的传入来实现多个行为 return fileReadInterface.process(bufferedReader); } }

第五步:拼接后,完整代码如下:

public class FileReaderDemo { public static void main(String[] args) throws IOException { // 第三步: // lambda表达式1 传给 函数式接口:只读取一行 FileReadInterface fileReadInterface = reader -> reader.readLine(); // lambda表达式2 传给 函数式接口:只读取两行 FileReadInterface fileReadInterface2 = reader -> reader.readLine() + reader.readLine(); // 最后一步: 不同的函数式接口的实现,表现出不同的行为 String str1 = processFile(fileReadInterface); String str2 = processFile(fileReadInterface2); System.out.println(str1); System.out.println(str2); } // 第四步: 读取文件方法,接受函数式接口作为参数 public static String processFile(FileReadInterface fileReadInterface) throws IOException { try( BufferedReader bufferedReader = new BufferedReader(new FileReader("./test.txt"))){ // 调用函数式接口中的抽象方法来处理数据 return fileReadInterface.process(bufferedReader); } } // 第一步: public static String processFile() throws IOException { try( BufferedReader bufferedReader = new BufferedReader(new FileReader("./test.txt"))){ return bufferReader.readLine(); } } } // 第二步: 我们手写的函数式接口 @FunctionalInterface interface FileReadInterface{ String process(BufferedReader reader) throws IOException; }

其实你会发现,我们手写的这个函数式接口,其实就是Function<T>去除泛型化后的接口,如下所示:

@FunctionalInterface public interface Function<T, R> { // 都是接受一个参数,返回另一个参数 R apply(T t); }

下面我们列出Java中常用的一些函数式接口,你会发现自带的已经够用了,基本不会需要我们自己去写

这里的手写只是为了自己实现一遍,可以加深理解程度

6. 常用的函数式接口

常用的函数式接口

7. 什么是方法引用

我们先看一个例子

前面我们写的lambda表达式,其实还可以简化,比如

// 简化前 Function<Cat, Integer> function = c->c.getAge(); // 简化后 Function<Cat, Integer> function2 = Cat::getAge;

其中简化后的Cat::getAge,我们就叫做方法引用

方法引用就是引用类或对象的方法

下面我们列出方法引用的三种情况:

Object::instanceMethod(对象的实例方法)

Class::staticMethod(类的静态方法)

Class::instanceMethod(类的实例方法)

像我们上面举的例子就是第三种:类的实例方法

下面我们用代码演示上面的三种方法:

public class ReferenceDemo { public static void main(String[] args) { // 第一种:引用对象的实例方法 Cat cat = new Cat(1); Function<Cat, Integer> methodRef1 = cat::getSum; // 第二种:引用类的静态方法 Supplier<Integer> methodRef2 = Cat::getAverageAge; // 第三种:引用类的实例方法 Function<Cat, Integer> methodRef3 = Cat::getAge; } } class Cat { int age; public Cat(int age) { this.age = age; } // 获取猫的平均年龄 public static int getAverageAge(){ return 15; } // 获取两只猫的年龄总和 public int getSum(Cat cat){ return cat.getAge() + this.getAge(); } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }

为啥要用这个方法引用呢?

方法引用好比lambda表达式的语法糖,语法更加简洁,清晰

一看就知道是调用哪个类或对象的哪个方法

8. 什么是构造引用

上面介绍了方法引用,就是直接引用某个方法

这里的构造引用同理可得,就是引用某个类的构造方法

构造引用的表达式为:Class::new,仅此一种

如果你有多个构造函数,那编译器会自己进行推断参数(你看看,多好,多简洁)

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxygp.html