【java8新特性】——方法引用(四)

一、简介

方法引用是java8的新特性之一, 可以直接引用已有Java类或对象的方法或构造器。方法引用与lambda表达式结合使用,可以进一步简化代码。
来看一段简单代码:

    public static void main(String[] args) {List<String> strList = Arrays.asList(new String[] { "a", "c", "b" });strList.stream().sorted((s1, s2) -> s1.compareToIgnoreCase(s2)).forEach(s -> System.out.println(s));}

上述程序生成一个Stream流,对流中的字符串进行排序并遍历打印。程序中采用lambda表达式的方式代替匿名类简化了代码,然而代码中两处lambda表达式都仅仅调用的是一个已存在的方法:String.compareToIgnoreCase、System.out.println,这种情况可以用方法引用来简化:

    public static void main(String[] args) {List<String> strList = Arrays.asList(new String[] { "a", "c", "b" });strList.stream().sorted(String::compareToIgnoreCase).forEach(System.out::println);}

对比一下可以看到,上述程序分别采用了类的任意对象的实例方法引用和特定对象的实例方法引用两种方法引用形式(下一章会讲述),采用方法引用的方式可以简化lambda表达式的写法。

二、方法引用的具体使用

java8方法引用有四种形式:

  • 静态方法引用       :   ClassName :: staticMethodName
  • 构造器引用        :   ClassName :: new
  • 类的任意对象的实例方法引用:   ClassName :: instanceMethodName
  • 特定对象的实例方法引用  :   object :: instanceMethodName

lambda表达式可用方法引用代替的场景可以简要概括为:lambda表达式的主体仅包含一个表达式,且该表达式仅调用了一个已经存在的方法。方法引用的通用特性方法引用所使用方法的入参和返回值与lambda表达式实现的函数式接口的入参和返回值一致。

2.1 静态方法引用

静态方法引用的语法格式为: 类名::静态方法名 ,如
System.out::println 等价于lambda表达式 s -> System.out.println(s) ,代码示例:

public class Test
{public static void main(String[] args){//lambda表达式使用:Arrays.asList(new String[] {"a", "c", "b"}).stream().forEach(s -> Test.println(s));//静态方法引用:Arrays.asList(new String[] {"a", "c", "b"}).stream().forEach(Test::println);}public static void println(String s){System.out.println(s);}
}

静态方法引用适用于lambda表达式主体中仅仅调用了某个类的静态方法的情形。

2.2 构造器引用

构造器引用的语法格式为: 类名::new ,如() -> new ArrayList() 等价于 ArrayList::new,代码示例:

Supplier<List<String>> supplier1= () -> new  ArrayList<String>();

等价于

Supplier<List<String>> supplier = ArrayList<String>::new;

构造器引用适用于lambda表达式主体中仅仅调用了某个类的构造函数返回实例的场景。

2.3 类的任意对象的实例方法引用

类的任意对象的实例方法引用的语法格式为: 类名::实例方法名 , 这种方法引用相对比较复杂,我们来看示例:

一、示例1

  Arrays.sort(strs,(s1,s2)->s1.compareToIgnoreCase(s2));

等价于

  Arrays.sort(strs, String::compareToIgnoreCase);

上述示例中,strs为一个String数组,lambda表达式(s1,s2)->s1.compareToIgnoreCase(s2)实现函数式接口的是Comparator接口, 我们看下jdk8中Comparator接口的源码(截取部分):

  @FunctionalInterfacepublic interface Comparator<T> {int compare(T o1, T o2);}

而String类的compareToIgnoreCase方法源码为:

    public int compareToIgnoreCase(String str) {return CASE_INSENSITIVE_ORDER.compare(this, str);}

可以发现函数式接口Comparator的compare方法比String类的compareToIgnoreCase方法多了一个String类型的入参。看到这里对类的任意对象的实例方法引用的使用可能似懂非懂,下面我们看一个自己实现一个类的任意对象的实例方法引用的示例(示例2)。

二、示例2

public class Student
{private String name;private Integer score;public void setNameAndScore(String name, Integer score){this.name = name;this.score = score;System.out.println("Student "+  name +"'s score is " + score);}public static void main(String[] args){/*lambda表达式的用法:TestInterface testInterface = (student, name, score) -> student.setNameAndScore(name, score);*///类的任意对象的实例方法引用的用法:TestInterface testInterface = Student::setNameAndScore;testInterface.set(new Student(), "DoubleBin", 100);}@FunctionalInterfaceinterface TestInterface{// 注意:入参比Student类的setNameAndScore方法多1个Student对象,除第一个外其它入参类型一致public void set(Student d, String name, Integer score);}
}

看完上述代码,我们可以总结出类的任意对象的实例方法引用的特性为:

1、方法引用的通用特性:方法引用所使用方法的入参和返回值与lambda表达式实现的函数式接口的入参和返回值一致;
2、lambda表达式的第一个入参为实例方法的调用者,后面的入参与实例方法的入参一致。

2.4 特定对象的实例方法引用

特定对象的实例方法引用的语法格式为: 对象::实例方法名 , 示例代码:

public class Test
{public static void main(String[] args){Test test = new Test();// lambda表达式使用:Arrays.asList(new String[] {"a", "c", "b"}).stream().forEach(s -> test.println(s));// 特定对象的实例方法引用:Arrays.asList(new String[] {"a", "c", "b"}).stream().forEach(test::println);}public void println(String s){System.out.println(s);}
}

特定对象的实例方法引用适用于lambda表达式的主体中仅仅调用了某个对象的某个实例方法的场景。

三、总结

方法引用使用运算符::连接类(或对象)与方法名称(或new)实现在特定场景下lambda表达式的简化表示,使用时要注意方法引用的使用场景及各种方法引用的特性。使用方法引用的好处是能够更进一步简化代码编写,使代码更简洁。
然而作者认为,方法引用代替lambda表达式对代码的简化程度远远没有lambda表达式代替匿名类的简化程度大, 有时反而增加了代码的理解难度(如2.3节:类的任意对象的实例方法引用),且使用场景的局限性不利于增加或修改代码,个人认为有时没有必要刻意使用方法引用~


  • 【java8新特性】——lambda表达式与函数式接口详解(一)

  • 【java8新特性】——Stream API详解(二)

  • 【java8新特性】——Optional详解(三)

  • 【java8新特性】——方法引用(四)

  • 【java8新特性】——默认方法(五)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/557287.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL 排名函数.md

概述 MySQL 自带的排名的函数&#xff0c;主要有&#xff1a; row_number()rank()dense_rank()ntile() 测试数据 测试数据如下所示&#xff1a; row_number() 函数 用法如下&#xff1a; SELECT row_number() OVER (ORDER BY Salary DESC) row_num,Salary FROMEmployee查…

【java8新特性】——默认方法(五)

一、简介 默认方法是指接口的默认方法&#xff0c;它是java8的新特性之一。顾名思义&#xff0c;默认方法就是接口提供一个默认实现&#xff0c;且不强制实现类去覆写的方法。默认方法用default关键字来修饰。 默认方法可以解决的痛点&#xff1a; 在java8之前&#xff0c;修…

Java 序列化总结.md

概述 序列化&#xff1a;将对象写入到 IO 流中反序列化&#xff1a;从 IO 流中恢复对象 实现方法 实现 Serializable 或者 Externalizable Serializable&#xff1a;标记接口&#xff0c;不用实现任何方法&#xff0c;可以指定序列化 IDExternalizable&#xff1a;增强的序…

多线程买票案例

测试类 package thead;public class testThread {public static void main(String [] arg){Tickets ticket new Tickets();Thread t1 new Thread(ticket,"窗口一&#xff1a;");Thread t2 new Thread(ticket,"窗口二&#xff1a;");Thread t3 new Thr…

深度学习auc_机器学习集成学习与模型融合!

↑↑↑关注后"星标"Datawhale每日干货 & 每月组队学习&#xff0c;不错过Datawhale干货 作者&#xff1a;李祖贤&#xff0c;深圳大学&#xff0c;Datawhale高校群成员对比过kaggle比赛上面的top10的模型&#xff0c;除了深度学习以外的模型基本上都是集成学习的…

常用并发工具类(锁和线程间通信工具类)

常用并发工具类总结 JUC 下的常用并发工具类&#xff08;锁和线程间通信工具类&#xff09;&#xff0c;主要包括 ReentrantLock、ReentrantReadWriteLock、CountDownLatch、CyclicBarrier、Semaphore、Exchanger ReentrantLock 和 ReentrantReadWriteLock ReentrantLock 是…

of方法:给集合一次性添加多个元素

of()方法只是Map&#xff0c;List&#xff0c;Set这三个接口的静态方法&#xff0c;其父类接口和子类实现并没有这类方法&#xff0c;比如 HashSet&#xff0c;ArrayList返回的集合是不可变的&#xff0c;再次添加会报错Set与Map集合不可以存储重复的元素&#xff0c;否则会报错…

数控车椭圆编程实例带图_数控车床编程教程,图文实例详解

一、数控车编程特点(1) 可以采用绝对值编程(用X、Z表示)、增量值编程(用U、W表示)或者二者混合编程。(2) 直径方向(X方向) 系统默认为直径编程&#xff0c;也可以采用半径编程&#xff0c;但必须更改系统设定。(3) X向的脉冲当量应取Z向的一半。(4)采用固定循环&#xff0c;简化…

常用并发工具类(并发集合类)

文章目录概述BlockingQueueArrayBlockingQueue数据存储相关属性阻塞特性相关属性主要方法LinkedBlockingQueueLinkedBlockingQueue 主要属性LinkedBlockingQueue 设计思想ConcurrentLinkedQueuePriorityBlockingQueuePriorityBlockingQueue 主要属性PriorityBlockingQueue 设计…

参考文献起止页码怎么写_毕业论文文献综述不会写?快来看看这篇文章(附含通用模板)...

文献综述是对所研究主题的现状进行客观的叙述和评论、寻求新的研究突破点。一个资料全面、研究深入的综述不仅可以帮助作者确立毕业论文的选题&#xff0c;还可以为论文的深入研究提供有力的支撑。本文分享一份"毕业论文文献综述万能模板",以供参考。一、文献综述的基…

常用并发工具类(线程池)

文章目录概述ThreadPoolExecutorThreadPoolExecutor 的主要属性Worker 主要属性线程池的状态线程池的状态流转线程池提交任务的执行流程线程数量的设置线程池的种类FixedThreadPoolCachedThreadPoolSingleThreadExecutorScheduledThreadPoolExecutorSingleThreadScheduledExecu…

【Java 8 新特性】Java Stream.of()用法示例

本页将介绍Java Stream.of方法示例。Stream.of用于为给定元素创建顺序流。我们可以传递单个元素或多个元素。 查看javadoc中Stream.of方法声明。 static <T> Stream<T> of(T t) 参数&#xff1a;传递单个元素。 返回&#xff1a;该方法返回一个包含一个元素的流。…

Java 类加载机制

文章目录概述类的生命周期类加载的时机类加载的主要 5 个阶段加载验证准备准备阶段初始值的含义解析符号引用直接引用解析阶段的理解静态绑定与动态绑定初始化类加载器类加载器与类之间的关系类加载器的种类双亲委派机制双亲委派机制设计目的破坏双亲委派机制破坏双亲委派机制的…

Java –什么是瞬态字段?

在Java中&#xff0c; transient字段在序列化过程中被排除。 简而言之&#xff0c;当我们将对象保存到文件中&#xff08;序列化&#xff09;时&#xff0c;所有transient字段都将被忽略。 1. POJO 瞬态 复查以下Person类&#xff1b; 薪水领域是transient 。 public class …

JVM 内存模型与内存分配方式

文章目录JVM 内存模型概述基于分代收集理论设计的垃圾收集器所管理的堆结构方法区的演变内存分配划分内存的方法划分内存时如何解决并发问题对象栈上分配基于分代收集理论的垃圾收集器管理下的内存分配规则对象优先分配在 Eden 区大对象直接进入老年代长期存活的对象将逐步进入…

image pil 图像保存_如何利用python中的PIL库做图像处理?

自从这个世界上出现了Python编程&#xff0c;一切都好像有了新的思路与进展&#xff0c;比如人工智能&#xff0c;还有我们常用的PS&#xff0c;你可知道Python也可以做图像处理&#xff0c;用的就是PIL库&#xff0c;还没有用过的&#xff0c;还没有发现的&#xff0c;还没有实…

GSON详解

GSON GSON弥补了JSON的许多不足的地方&#xff0c;在实际应用中更加适用于Java开发。在这里&#xff0c;我们主要讲解的是利用GSON来操作java对象和json数据之间的相互转换&#xff0c;包括了常见的对象序列化和反序列化的知识。 一、前言 因为json有2种类型&#xff1a; 一…

机器人 瓷砖墙面清洗_墙壁清洁机器人解析

1第一章绪论1.1课题的背景、目的及意义[1]壁面清洗爬壁机器人属于移动式服务机器人的一种&#xff0c;可在垂直壁面或顶部移动&#xff0c;完成其外表面的清洗作业。在工业机器人问世30多年后的今天&#xff0c;它已被世人看作是一种生产工具&#xff0c;在制造、装配及最近在服…

内存回收算法与 Hot Spot 算法实现细节

文章目录内存回收算法概述对象存活判定算法引用计数算法可达性分析算法垃圾收集算法分代收集理论标记-清除算法标记-复制算法半区复制算法Appel 式复制算法Appel 式复制算法的逃生门设计标记-整理算法HotSpot 虚拟机实现细节GC Root 枚举Hot Spot 实现 GC Root 枚举安全点与安全…

link st 量产工具_ST-Link资料03_ST-Link固件升级、驱动下载安装方法

说明&#xff1a;本文原创作者『strongerHuang』本文首发于微信公众号『嵌入式专栏』&#xff0c;同时也更新在我的个人网站&#xff1a;EmbeddedDevelop一、写在前面前两篇文章讲述的都是关于ST-Link的一些理论知识&#xff0c;建议初学者看看&#xff1a;ST-Link资料01_ST-Li…