博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java基础学习总结(69)——匿名内部类与Lambda表达式
阅读量:6302 次
发布时间:2019-06-22

本文共 3032 字,大约阅读时间需要 10 分钟。

前言

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
list = Arrays.asList("I", "love", "you", "too"); Collections.sort(list, new Comparator
{// 接口名 @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
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
add = (Long x, Long y) -> x + y;// 4 BinaryOperator
addImplicit = (x, y) -> x + y;// 5 类型推断

上述代码中,1展示了无参函数的简写;2处展示了有参函数的简写,以及类型推断机制;3是代码块的写法;4和5再次展示了类型推断机制。

自定义函数接口

自定义函数接口很容易,只需要编写一个只有一个抽象方法的接口即可。

// 自定义函数接口 @FunctionalInterface public interface ConsumerInterface
{ void accept(T t); }

有了上述接口定义,就可以写出类似如下的代码:

ConsumerInterface<String> consumer = str -> System.out.println(str);

进一步的,还可以这样使用:

class MyStream
{ private List
list; ... public void myForEach(ConsumerInterface
consumer){// 1 for(T t : list){ consumer.accept(t); } } } MyStream
stream = new MyStream
; stream.myForEach(str -> System.out.println(str));// 使用自定义函数接口书写Lambda表达式

参考文献

  1. The Java® Language Specification
  2. http://viralpatel.net/blogs/lambda-expressions-java-tutorial/
  3. 《Java 8函数式编程 [英]沃伯顿》

转载于:https://www.cnblogs.com/zhanghaiyang/p/7212806.html

你可能感兴趣的文章
如何为数据进行加密与解密,避免使用者窃取机密数据?
查看>>
TW实习日记:第13天
查看>>
Introduction to Locking in SQL Server
查看>>
leetcode:Power of Two
查看>>
完整教程--idea使用git进行项目管理
查看>>
代数之管见(孟道骥)第二讲:漫谈数学学习
查看>>
[Leetcode]27. Remove Element
查看>>
解析和文件上传漏洞
查看>>
徽章组件
查看>>
js判断计算机语言
查看>>
Linux CentOS 6.5 使用自带jdk修改环境变量
查看>>
看博客学学Android(十)
查看>>
基于开源项目的在线网络视频直播项目---前言
查看>>
目标检测的图像特征提取之(三)Haar特征
查看>>
通过哪些方式可以降低网站的跳出率
查看>>
修改HTML5 input placeholder 颜色及修改失效的解决办法
查看>>
认识委托
查看>>
Android学习笔记(十八)——再谈升级数据库
查看>>
(最小生成树) Borg Maze -- POJ -- 3026
查看>>
(字符串 键盘转换)Convert QWERTY to Dvorak -- zoj -- 5526
查看>>