读书笔记——《Java 8实战》系列之方法引用
来源:互联网 发布:js获取当前时间字符串 编辑:程序博客网 时间:2024/05/24 07:00
转自 http://www.wxueyuan.com/blog/articles/2017/10/19/1508379046077.html
在上一篇博客中,我们继续介绍了一些关于Lambda表达式的相关知识。在本篇博客中,我将向大家介绍一种通过调用特定方法来使Lambda表达式更简捷的办法——方法引用。事实上,方法引用就是让你根据已有的方法实现来创建Lambda表达式。
简单来说,方法引用的语法就是:
目标引用::方法名称
需要注意的是这里的方法名称后面不加圆括号(),因为我们并没有实际调用这个方法
方法引用大概分为三类:
类型方法引用示例指向静态方法的方法引用Class::staticMethod(如 Integer::parseInt)指向任意类型实例方法的方法引用Class::instanceMethod(如 String::length)指向现有对象的实例方法的方法引用object::instanceMethod(如 student::getHeight)第二种方法引用与第三种方法引用乍一看会让人有些迷惑,实际上第二种方法引用主要是用在当我们Lambda表达式的主体中调用参数对象的某个方法时,如:
(String s) -> s.length() 可以改写成 String::length
而第三种方法引用主要时用在当我们在调用一个外部对象的方法时,如:
() -> student.getHeight() 可以改写成 student::getHeight
下图是为三种不同类型的Lambda表达式构建方法引用的办法
接下来我就用一个例子——给学生利用不同策略来排序为大家总结一下,行为参数化,Lambda表达式(一),Lambda表达式(二),和本篇博客的重要内容。
- 首先是我们的Student实体类
class Student{ private String name; //学生姓名 private Integer avgScore; //平均成绩 private Integer height; //学生身高 public Student(String name, Integer avgScore, Integer height) { super(); this.name = name; this.avgScore = avgScore; this.height = height; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAvgScore() { return avgScore; } public void setAvgScore(int avgScore) { this.avgScore = avgScore; } public Integer getHeight() { return height; } public void setHeight(int height) { this.height = height; } @Override public String toString() { return this.getName(); } }
- Java 的API类库中已经提供了List的sort方法,我们不用去自己实现它,只需要传入一个Comparator类型的对象,list就可以按照它的规则来排序
void sort(Comparator<? super E> c)
- Comparator是一个函数式接口,它提供了一个比较两个对象大小的方法compare(T o1, T o2),返回一个int类型的值,该返回值可能为负数,0,或者正数,分别对应着o1小于,等于,或者大于o2。
//返回值可能为负数,0,或者正数,分别对应着o1小于,等于,或者大于o2 int compare(T o1, T o2);
- 要想将一个List中的学生以某种规则排序,我们以行为参数化的角度来考虑,第一种解决方案应该如下:
//实现一个Comparator接口的实体类StudentHeightComparator,通过比较两个学生的身高,来比较两个student对象的大小 class StudentHeightComparator implements Comparator<Student>{ @Override public int compare(Student s1, Student s2) { // TODO Auto-generated method stub return s1.getHeight().compareTo(s2.getHeight()); } public static void main(String[] args) { // TODO Auto-generated method stub List<Student> students = new ArrayList<>(); students.add(new Student("a",90,180)); students.add(new Student("b",80,175)); students.add(new Student("c",70,190)); //实例化StudentHeightComparator,并将其作为参数传入到sort方法中去 students.sort(new StudentHeightComparator()); System.out.println(students.toString()); }}
- 匿名类的机制可以一定程度上优化我们的第一种解决方案,它的解决方案应该如下:
public static void main(String[] args) { // TODO Auto-generated method stub List<Student> students = new ArrayList<>(); students.add(new Student("a",90,180)); students.add(new Student("b",80,175)); students.add(new Student("c",70,190)); //使用匿名类,我们就无需实现一个只需实例化一次的类StudentHeightComparator students.sort(new Comparator<Student>() { @Override public int compare(Student s1, Student s2) { // TODO Auto-generated method stub return s1.getHeight().compareTo(s2.getHeight()); } }); System.out.println(students.toString()); }
- 尽管匿名类一定程度上减少了方案一中啰嗦的代码,但我们可以使用Lambda表达式来使方案二变得更加简单:
public static void main(String[] args) { // TODO Auto-generated method stub List<Student> students = new ArrayList<>(); students.add(new Student("a",90,180)); students.add(new Student("b",80,175)); students.add(new Student("c",70,190)); //Comparator实际上代表了(T,T) -> int 的函数描述符 students.sort((s1,s2) -> s1.getHeight().compareTo(s2.getHeight())); System.out.println(students.toString()); }
- 现在我们来为实体类Student增加一个静态方法,来写出一个不一样的Lambda表达式:
class Student{ ...... public static int compareStudentByHeight(Student s1, Student s2) { return s1.getHeight().compareTo(s2.getHeight()); } } public static void main(String[] args) { List<Student> students = new ArrayList<>(); students.add(new Student("a",90,180)); students.add(new Student("b",80,175)); students.add(new Student("c",70,190)); //使用Student类的静态方法 students.sort((s1,s2) -> Student.compareStudentByHeight(s1,s2)); System.out.println(students.toString()); }
- 最后,我们使用方法引用来将上面的代码变得更加简洁,使得代码阅读起来就像问题描述的一样:
public static void main(String[] args) { List<Student> students = new ArrayList<>(); students.add(new Student("a",90,180)); students.add(new Student("b",80,175)); students.add(new Student("c",70,190)); //使用Student类的静态方法的方法引用 students.sort(Student::compareStudentByHeight); System.out.println(students.toString()); }
- 最后的这种解决方案呢,其实是用了我们上面提到的指向静态方法的方法引用,那么同学们能不能自己写出剩下的两种类型的方法引用呢?
指向任意类型实例方法的方法引用实例
class Student{ ...... //一个普通的实例方法 public int compareToStudentByHeight(Student s) { return this.getHeight().compareTo(s.getHeight()); } } public static void main(String[] args) { // TODO Auto-generated method stub List<Student> students = new ArrayList<>(); students.add(new Student("a",90,180)); students.add(new Student("b",80,175)); students.add(new Student("c",70,190)); //使用任意类型对象实例方法的Lambda表达式形式,等价于下一行代码 students.sort((s1,s2) -> s1.compareToStudentByHeight(s2)); //使用指向任意类型对象实例方法的方法引用,进一步简化了上一行代码 students.sort(Student::compareToStudentByHeight); System.out.println(students.toString()); }
指向现有对象的实例方法的方法引用
public static void main(String[] args) { // TODO Auto-generated method stub List<Student> students = new ArrayList<>(); students.add(new Student("a",90,180)); students.add(new Student("b",80,175)); students.add(new Student("c",70,190)); StudentComparatorProvider provider = new StudentComparatorProvider(); //使用指向现有对象的实例方法的Lambda表达式形式,等价于下一行代码 students.sort((s1,s2) -> provider.compareStudentByHeight(s1, s2)); //使用指向现有对象的实例方法的方法引用,进一步简化了上一行代码 students.sort(provider::compareStudentByHeight); System.out.println(students.toString()); }
- 除此之外,对于一个现有的构造函数,你可以利用它的名称和关键字new来创建一个它的引用,首先我们先稍微修改下我们的Student实体类,在实体类中分别提供无参,一个参数和两个参数的构造函数。
class Student{ private String name; //学生姓名 private Integer avgScore; //平均成绩 public Student() { this.name = "defaultName"; this.avgScore = 0; } public Student(String name) { this.name = name; this.avgScore = 0; } public Student(String name, Integer avgScore) { this.name = name; this.avgScore = avgScore; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAvgScore() { return avgScore; } public void setAvgScore(int avgScore) { this.avgScore = avgScore; } @Override public String toString() { return "姓名:"+this.getName()+" 平均分: "+this.getAvgScore(); } }
- 假如使用new Student()构造函数,它的函数签名是() -> Student, 符合Supplier 的() -> T 的函数签名,因此我们可以用以下几种不同的方法创建一个Student实例:
public static void main(String[] args) { //使用无参构造函数创建实例 Student student1 = new Student(); System.out.println(student1.toString()); //使用Lambda表达式创造实例,等价于下面使用方法引用创建实例 Supplier<Student> s1 = () -> new Student(); Student student2 = s1.get(); System.out.println(student2.toString()); //使用方法引用进一步简化Lambda表达式的写法 Supplier<Student> s= Student::new; Student student3 = s.get(); System.out.println(student3.toString()); }
- 假如使用new Student(String name)构造函数,它的函数签名是(String) -> Student,符合Function
public static void main(String[] args) { //使用一个参数构造函数创建实例 Student student1 = new Student("Jesmin"); System.out.println(student1.toString()); //使用Lambda表达式创造实例,等价于下面使用方法引用创建实例 Function<String,Student> f = s -> new Student(s); Student student2 = f.apply("Jesmin"); System.out.println(student2.toString()); //使用方法引用进一步简化Lambda表达式的写法 Function<String,Student> f2= Student::new; Student student3 = f2.apply("Jesmin"); System.out.println(student3.toString()); }
- 假如使用new Student(String name, Integer avgScore)构造函数,他的函数签名是(String,Integer) -> Student,符合BiFunction
public static void main(String[] args) { //使用两个参数构造函数创建实例 Student student1 = new Student("Jesmin",90); System.out.println(student1.toString()); //使用Lambda表达式创造实例,等价于下面使用方法引用创建实例 BiFunction<String,Integer,Student> bf = (s,i) -> new Student(s,i); Student student2 = bf.apply("Jesmin",90); System.out.println(student2.toString()); //使用方法引用进一步简化Lambda表达式的写法 BiFunction<String,Integer,Student> bf2= Student::new; Student student3 = bf2.apply("Jesmin",90); System.out.println(student3.toString()); }
阅读全文
1 0
- 读书笔记——《Java 8实战》系列之方法引用
- 读书笔记——《Java 8实战》系列之行为参数化
- 读书笔记——《Java 8实战》系列之Lambda表达式(一)
- 读书笔记——《Java 8实战》系列之Lambda表达式(二)
- 读书笔记——《Java 8实战》系列之复合Lambda表达式
- 读书笔记——《深入理解Java虚拟机》系列之回收对象算法与四种引用类型
- Java 8实战之读书笔记一:内容简介
- Java 8实战之读书笔记二:基础知识
- 《Effective java》读书笔记——过期引用
- Java 8实战之读书笔记四:高效Java 8编程
- Java 8实战之读书笔记五:超越Java 8
- java并发编程实战——读书笔记
- java8系列之方法引用
- Java 8实战之读书笔记三:函数式数据处理
- Java 8之方法引用(Method References)
- Java 8之方法引用(Method References)
- 《Spring实战》读书笔记——第一章 Spring之旅
- 读书笔记——《深入理解Java虚拟机》系列之四种垃圾收集算法
- 【51Nod
- 用一种新奇简单的思想,看待傅里叶变换(原文:如果看了此文你还不懂傅里叶变换,那就过来掐死我吧)
- [BFS] POJ 3126
- 10月31日解题报告
- java对redis基本操作
- 读书笔记——《Java 8实战》系列之方法引用
- css盒模型的padding 和margin
- 2015-07-13 leetcode:Longest Substring Without Repeating Characters
- 基础数据结构_模板
- poj 1564 Sum It Up
- springmvc的简单介绍
- 存储系统的分类
- flask web开发-用户验证代码分析(五)
- Javascript中最常用的61个经典技巧