Java基础学习总结(69)——匿名内部类与Lambda表达式
前言
Java Labmda表达式的一个重要用法是简化某些匿名内部类(Anonymous Classes
)的写法。实际上Lambda表达式并不仅仅是匿名内部类的语法糖,JVM内部是通过invokedynamic指令来实现Lambda表达式的。具体原理放到下一篇。本篇我们首先感受一下使用Lambda表达式带来的便利之处。
取代某些匿名内部类
本节将介绍如何使用Lambda表达式简化匿名内部类的书写,但Lambda表达式并不能取代所有的匿名内部类,只能用来取代函数接口(Functional Interface)的简写。先别在乎细节,看几个例子再说。
例子1:无参函数的简写
如果需要新建一个线程,一种常见的写法是这样:
// JDK7 匿名内部类写法 new Thread(new Runnable{// 接口名 @Override public void run{// 方法名 System.out.println("Thread run"); } }).start;
上述代码给Tread
类传递了一个匿名的Runnable
对象,重载Runnable
接口的run
方法来实现相应逻辑。这是JDK7以及之前的常见写法。匿名内部类省去了为类起名字的烦恼,但还是不够简化,在Java
8中可以简化为如下形式:
// JDK8 Lambda表达式写法 new Thread( -> System.out.println("Thread run")// 省略接口名和方法名 ).start;
上述代码跟匿名内部类的作用是一样的,但比匿名内部类更进一步。这里连接口名和函数名都一同省掉了,写起来更加神清气爽。如果函数体有多行,可以用大括号括起来,就像这样:
// JDK8 Lambda表达式代码块写法 new Thread( -> { System.out.print("Hello"); System.out.println(" Hoolee"); } ).start;
例子2:带参函数的简写
如果要给一个字符串列表通过自定义比较器,按照字符串长度进行排序,Java 7的书写形式如下:
// JDK7 匿名内部类写法 List<String> list = Arrays.asList("I", "love", "you", "too"); Collections.sort(list, new Comparator<String>{// 接口名 @Override public int compare(String s1, String s2){// 方法名 if(s1 == null) return -1; if(s2 == null) return 1; return s1.length-s2.length; } });
上述代码通过内部类重载了Comparator
接口的compare
方法,实现比较逻辑。采用Lambda表达式可简写如下:
// JDK8 Lambda表达式写法 List<String> list = Arrays.asList("I", "love", "you", "too"); Collections.sort(list, (s1, s2) ->{// 省略参数表的类型 if(s1 == null) return -1; if(s2 == null) return 1; return s1.length-s2.length; });
上述代码跟匿名内部类的作用是一样的。除了省略了接口名和方法名,代码中把参数表的类型也省略了。这得益于javac
的类型推断机制,编译器能够根据上下文信息推断出参数的类型,当然也有推断失败的时候,这时就需要手动指明参数类型了。注意,Java是强类型语言,每个变量和对象都必需有明确的类型。
简写的依据
也许你已经想到了,能够使用Lambda的依据是必须有相应的函数接口(函数接口,是指内部只有一个抽象方法的接口)。这一点跟Java是强类型语言吻合,也就是说你并不能在代码的任何地方任性的写Lambda表达式。实际上Lambda的类型就是对应函数接口的类型。Lambda表达式另一个依据是类型推断机制,在上下文信息足够的情况下,编译器可以推断出参数表的类型,而不需要显式指名。Lambda表达更多合法的书写形式如下:
// Lambda表达式的书写形式 Runnable run = -> System.out.println("Hello World");// 1 ActionListener listener = event -> System.out.println("button clicked");// 2 Runnable multiLine = -> {// 3 代码块 System.out.print("Hello"); System.out.println(" Hoolee"); }; BinaryOperator<Long> add = (Long x, Long y) -> x + y;// 4 BinaryOperator<Long> addImplicit = (x, y) -> x + y;// 5 类型推断
上述代码中,1展示了无参函数的简写;2处展示了有参函数的简写,以及类型推断机制;3是代码块的写法;4和5再次展示了类型推断机制。
自定义函数接口
自定义函数接口很容易,只需要编写一个只有一个抽象方法的接口即可。
// 自定义函数接口 @FunctionalInterface public interface ConsumerInterface<T>{ void accept(T t); }
有了上述接口定义,就可以写出类似如下的代码:
ConsumerInterface<String> consumer = str -> System.out.println(str);
进一步的,还可以这样使用:
class MyStream<T>{ private List<T> list; ... public void myForEach(ConsumerInterface<T> consumer){// 1 for(T t : list){ consumer.accept(t); } } } MyStream<String> stream = new MyStream<String>; stream.myForEach(str -> System.out.println(str));// 使用自定义函数接口书写Lambda表达式
参考文献
- The Java® Language Specification
- http://viralpatel.net/blogs/lambda-expressions-java-tutorial/
- 《Java 8函数式编程 [英]沃伯顿》
Java基础学习总结(69)——匿名内部类与Lambda表达式的更多相关文章
- Java基础学习总结(44)——10个Java 8 Lambda表达式经典示例
Java 8 刚于几周前发布,日期是2014年3月18日,这次开创性的发布在Java社区引发了不少讨论,并让大家感到激动.特性之一便是随同发布的lambda表达式,它将允许我们将行为传到函数里.在Ja ...
- 尚学堂JAVA基础学习笔记
目录 尚学堂JAVA基础学习笔记 写在前面 第1章 JAVA入门 第2章 数据类型和运算符 第3章 控制语句 第4章 Java面向对象基础 1. 面向对象基础 2. 面向对象的内存分析 3. 构造方法 ...
- [转帖]java基础学习总结——多态(动态绑定)
https://www.cnblogs.com/xdp-gacl/p/3644035.html 多态的概念 java基础学习总结——多态(动态绑定) 一.面向对象最核心的机制——动态绑定,也叫多态
- Java基础学习(2)
Java基础学习(二) 面向对象 对象:客观存在的事物 面向对象:人具体关注的事物的某些信息 类:是模子,确定对象会拥有的特征(属性)和行为(方法) 对象的属性:对象具有的各种特征 对象的方法:对象能 ...
- java基础学习笔记五(抽象类)
java基础学习总结——抽象类 抽象类介绍
- Java 从匿名内部类到Lambda表达式
匿名内部类和Lambda表达式有很多类似之处,首先都是在使用的时候才对接口进行实现,只是Lambda接口中只能由一个需要被实现的方法. 所有的Lambda表达式都可以 由匿名内部类改写: interf ...
- Java基础学习-- 继承 的简单总结
代码参考:Java基础学习小记--多态 为什么要引入继承? 还是做一个媒体库,里面可以放CD,可以放DVD.如果把CD和DVD做成两个没有联系的类的话,那么在管理这个媒体库的时候,要单独做一个添加CD ...
- Java基础学习中一些词语和语句的使用
在Java基础学习中,我们刚接触Java会遇到一些词和语句的使用不清的情况,不能很清楚的理解它的运行效果会是怎么样的,如:break,continue在程序中运行效果及跳转位置, 1.先来看看brea ...
- Java基础学习笔记总结
Java基础学习笔记一 Java介绍 Java基础学习笔记二 Java基础语法之变量.数据类型 Java基础学习笔记三 Java基础语法之流程控制语句.循环 Java基础学习笔记四 Java基础语法之 ...
- 转载-java基础学习汇总
共2页: 1 2 下一页 Java制作证书的工具keytool用法总结 孤傲苍狼 2014-06-24 11:03 阅读:25751 评论:3 Java基础学习总结——Java对象的序列化和 ...
随机推荐
- 特征选择--->卡方选择器
特征选择(Feature Selection)指的是在特征向量中选择出那些“优秀”的特征,组成新的.更“精简”的特征向量的过程.它在高维数据分析中十分常用,可以剔除掉“冗余”和“无关”的特征,提升学习 ...
- 常用进制的转换、进制数的and与or或xor异或运算
[十进制转换成其他进制]例:将25转换为二进制数 解: 25÷2=12 余数1 12÷2=6 余数0 6÷2=3 余数0 3÷2=1 余数1 1÷2=0 余数1 所 ...
- PCB javascript解析钻孔(Excellon)格式实现方法
解析钻孔(Excellon)格式前首先得了解此格式,这样才能更好的解析呀. 一个钻孔里面包含的基本信息如下: 1.单位:公式mm,英制inch 2.省零方式:前省零,后省零 3.坐标方式:绝对坐标,相 ...
- codevs1669 运输装备(背包dp)
1669 运输装备 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 德国放松对英国的进攻后,把矛头指向了东北——苏联 ...
- Linux下sublime 无法输入中文的解决
个人认为linux下的编辑器,对于小白来说,最好用的就是sublime了,但是,安装之后敲代码无法输入中文 ,很尴尬. 百度后,发现了解决方法. 项目链接:https://github.com/lyf ...
- akka设计模式系列-Backend模式
上一节我们介绍了Akka使用的基本模式,简单点来说就是,发消息给actor,处理结束后返回消息.但这种模式有个缺陷,就是一旦某个消息处理的比较慢,就会阻塞后面所有消息的处理.那么有没有方法规避这种阻塞 ...
- 大圆那些事 LIBRARY_PATH和LD_LIBRARY_PATH环境变量的区别
LIBRARY_PATH和LD_LIBRARY_PATH环境变量的区别 LIBRARY_PATH和LD_LIBRARY_PATH是Linux下的两个环境变量,二者的含义和作用分别如下: LIBRARY ...
- 你真的知道GET和POST两种基本请求方法的区别吗?
GET和POST是HTTP请求的两种基本方法,要说它们的区别,接触过WEB开发的人都能说出一二. 最直观的区别就是GET把参数包含在URL中,POST通过request body传递参数. 你可能自己 ...
- Prime Ring Problem -- 第一个真正意义上的 搜索
这个搜索............搜的我头都大了.......不过还是 懂了那么一点点...哈哈 从3/7晚上 做到3/8晚上------从女生到妇女 我都用来做着一道题了......... 所谓的 ...
- 服务器上oracle的监听设置
1.查看本机的计算机名 2.修改etc/host 3.修改oracle的listener.ora(我服务器上的路径:) 4.修改tnsnames.ora(和上边文件一个目录)