Java 8 Lambda
来源:互联网 发布:淘宝流量充值如何退款 编辑:程序博客网 时间:2024/05/17 23:45
为什么需要Lambda表达式
不要纠结什么是Lambda表达式,什么是函数式编程,先来看一下Java8新的语法特性带来的便利之处,相信你会过目不忘的。
在有Lambda表达式之前,要新建一个线程,需要这样写:
package com.lambdatest;/** * Created by root on 3/6/17. */public class Main { public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { System.out.println("Thread run()"); } }).start(); }}
有Lambda表达式之后,则可以这样写:
package com.lambdatest;/** * Created by root on 3/6/17. */public class Main { public static void main(String[] args) { new Thread( () -> System.out.println("Thread run()") ).start(); }}
正如你所见,之前无用的模板代码不见了!如上所示,Lambda表达式一个常见的用法是取代(某些)匿名内部类,但Lambda表达式的作用不限于此。
Lambda表达式的原理
刚接触Lambda表达式可能觉得它很神奇:不需要声明类或者方法的名字,就可以直接定义函数。这看似是编译器为匿名内部类简写提供的一个小把戏,但事实上并非如此,Lambda表达式实际上是通过invokedynamic指令来实现的。先别管这么多,下面是Lambda表达式几种可能的书写形式,“看起来”并不是很难理解。
Runnable run = () -> System.out.println("Hello World"); ActionListener listener = event -> System.out.println("button clicked"); Runnable multiline = () -> { System.out.println("Hello"); System.out.println("World"); }; BinaryOperator<Long> add = (Long x, Long y) -> x + y; BinaryOperator<Long> addImplicit = (x, y) -> x + y;
通过上面的代码可以发现:
- Lambda表达式是有类型的,赋值操作的左边就是类型。Lambda表达式的类型实际上是对应接口的类型。
- Lambda表达式可以包含多行代码,需要用大括号把代码块括起来,就像写函数一样。
- 大多数时候,Lambda表达式的参数表可以省略类型,这得益于javac的类型推导机制,编译器可以根据上下文推导出类型信息。
表面上看起来每个Lambda表达式都是原来匿名内部类的简写形式,该内部类实现了某个函数接口(Functional Interface),但事实上比这稍微复杂一些,这里不再展开。所谓函数接口是指内部只有一个接口函数的接口。Java是强类型语言,无论有没有显式指明,每个变量和对象都必须有明确的类型,没有显式指定的时候编译器会尝试确定类型。Lambda表达式的类型就是对应函数接口的类型。
Lambda表达式和Stream
Lambda表达式的另一个重要的用法,是和Stream一起使用。Stream is a sequence of elements supporting sequential and parallel aggregate operations。Stream就是一组元素的序列,支持对这些元素进行各种操作,而这些操作是通过Lambda表达式指定的。可以把Stream看作Java Collection的一种视图,就像迭代器是容器的一种视图那样(但Stream不会修改容器中的内容)。下面例子展示了Stream的常见用法:
例子1
假设需要从一个字符串列表中选出以数字开头的字符串并输出,Java 7之前是这样写的:
package com.lambdatest;import java.util.Arrays;import java.util.List;/** * Created by root on 3/6/17. */public class Main { public static void main(String[] args) { List<String> list = Arrays.asList("1one", "two", "three", "4four"); for(String str : list) { if(Character.isDigit(str.charAt(0))) { System.out.println(str); } } }}
而Java 8需要这样写:
package com.lambdatest;import java.util.Arrays;import java.util.List;/** * Created by root on 3/6/17. */public class Main { public static void main(String[] args) { List<String> list = Arrays.asList("1one", "two", "three", "4four"); list.stream() // 得到容器的Stream .filter(str -> Character.isDigit(str.charAt(0))) // 选出以数字开头的字符串 .forEach(str -> System.out.println(str)); // 输出字符串 }}
上述代码首先调用list.stream()方法得到容器的Stream,然后调用filter()方法过滤出以数字开头的字符串,最后调用forEach()方法输出结果。
使用Stream有两个明显的好处:
- 减少了模板代码,只用Lambda表达式指名所需操作,代码语义更加明确,便于阅读。
- 将外部迭代改成了Stream的内部迭代,方便了JVM本身对迭代过程进行优化(比如可以并行迭代)。
例子2
假设要从一个字符串列表中,选出所有不以数字开头的字符串,并将其转换成大写形式,并把结果放到新的集合当中。Java 8的书写代码如下:
package com.lambdatest;import java.util.Arrays;import java.util.List;import java.util.Set;import java.util.stream.Collectors;/** * Created by root on 3/6/17. */public class Main { public static void main(String[] args) { List<String> list = Arrays.asList("1one", "two", "three", "4four"); Set<String> strSet = list.stream() // 得到容器的Stream .filter(str -> !Character.isDigit(str.charAt(0))) // 选出不以数字开头的字符串 .map(String::toUpperCase) // 转换成大写形式 .collect(Collectors.toSet()); // 生成结果集 }}
上面的代码首先调用list.stream()方法得到容器的Stream,然后调用filter()方法选出不以数字开头的字符串,之后调用map()方法将字符串转换成大写形式,最后调用collect()方法将结果转换成Set。这个例子还向我们展示了方法引用(method references),以及收集器(collector)的用法,这里不再展开说明。
通过这个例子我们看到了Stream链式操作,即多个操作可以连成一串。不用担心这会导致对容器的多次迭代,因为不是每个Stream操作都会立即执行的。Stream的操作分为两类,一类是中间操作(intermediate operations),另一类是结束操作(terminal operations),只有结束操作才会导致真正的代码执行,中间操作只会做一些标记,表示需要对Stream进行某种操作,这意味着可以在Stream上通过关联多种操作,但最终只需要一次迭代。如果你熟悉Spark RDD,对这些概念应该不陌生。
0 0
- Java 8中的Lambda
- lambda in java 8
- Java 8 lambda表达式
- java 8 lambda
- Java 8之Lambda
- Java 8 Lambda表达式
- Java 8 Lambda
- Java 8 lambda表达式
- Java 8 Lambda 技巧
- Java 8 Lambda 表达式
- Java 8 Lambda表达式
- Java 8: Lambda Expression
- 理解Java 8 Lambda
- java 8 Lambda排序
- Java 8 lambda初试
- Java 8 Lambda 表达式
- Java 8 Lambda表达式
- Java 8 Lambda
- git和github经常使用的命令集合
- java__X的平方根。设计函数int sqrt(int x),计算 xx 的平方根。
- 逆元
- 2.2-2 整数四则运算
- 半双工和全双工的区别
- Java 8 Lambda
- 静态链表单向实现
- ImageView剖析二—(示例详解ImageView属性的使用)
- C++基础知识复习--字符串
- 欧拉函数
- 欢迎使用CSDN-markdown编辑器
- 共享密钥与公开密钥
- STM32
- 从百度统计看到的一些有意思的事情