解问 lambda表达式
目录
1.0 何为Lambda
1.1 Lambda语法特征
1.2 Lambda实例
1.3 Lambda中的stream
1.4 Lambda 中的 stream 效率
1.0 何为Lambda
所谓 “Lambda 表达式”(lambda expression)它是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Lambda表达式可以表示闭包(注意和数学传统意义上的不同)。如果想深入可以去这位仁兄的博客看看 点我进去 这里做个了解。
1.1 Lambda语法特征
认准 " - > " Lambad 老字号
可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
在 Lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量。
String first = "";
Comparator<String> comparator = (first, second) -> Integer.compare(first.length(), second.length()); //编译会出错
1.2 Lambda实例
从语法特征分析出的傻白甜代码片段
// 1. 不需要参数,返回值为 5
() -> 5 // 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x // 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y // 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y // 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
public class Java8Tester {
public static void main(String args[]){
Java8Tester tester = new Java8Tester(); // 类型声明
MathOperation addition = (int a, int b) -> a + b; // 不用类型声明
MathOperation subtraction = (a, b) -> a - b; // 大括号中的返回语句
MathOperation multiplication = (int a, int b) -> { return a * b; }; // 没有大括号及返回语句
MathOperation division = (int a, int b) -> a / b; System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
System.out.println("10 / 5 = " + tester.operate(10, 5, division)); // 不用括号
GreetingService greetService1 = message ->
System.out.println("Hello " + message); // 用括号
GreetingService greetService2 = (message) ->
System.out.println("Hello " + message); greetService1.sayMessage("Runoob");
greetService2.sayMessage("Google");
} interface MathOperation {
int operation(int a, int b);
} interface GreetingService {
void sayMessage(String message);
} private int operate(int a, int b, MathOperation mathOperation){
return mathOperation.operation(a, b);
}
}
Lambda表达式应用场景
使用 ( ) - { } 来代替匿名类 代码来自这位仁兄 点我进去
//未使用Lambda
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("no use lambda");
}
});
//使用之后
Thread t2 = new Thread(() -> System.out.println("use lambda"));
我们看到相对而言Lambda表达式要比匿名类要优雅简洁很多~。
以流水线的方式处理数据
List<Integer> integers = Arrays.asList(4, 5, 6,1, 2, 3,7, 8,8,9,10); List<Integer> evens = integers.stream().filter(i -> i % 2 == 0)
.collect(Collectors.toList()); //过滤出偶数列表 [4,6,8,8,10]<br>
List<Integer> sortIntegers = integers.stream().sorted()
.limit(5).collect(Collectors.toList());//排序并且提取出前5个元素 [1,2,3,4,5] List<Integer> squareList = integers.stream().map(i -> i * i).collect(Collectors.toList());//转成平方列表 int sum = integers.stream().mapToInt(Integer::intValue).sum();//求和 Set<Integer> integersSet = integers.stream().collect(Collectors.toSet());//转成其它数据结构比如set Map<Boolean, List<Integer>> listMap = integers.stream().collect(Collectors.groupingBy(i -> i % 2 == 0)); //根据奇偶性分组 List<Integer> list = integers.stream().filter(i -> i % 2 == 0).map(i -> i * i).distinct().collect(Collectors.toList());//复合操作
1.3 Lambda表达式中的Stream
在java 8 中 Stream 不是集合元素,它不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。原始版本的 Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作;高级版本的 Stream,用户只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”、“获取每个字符串的首字母”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。
Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返。而和迭代器又不同的是,Stream 可以并行化操作,迭代器只能命令式地、串行化操作。顾名思义,当使用串行方式去遍历时,每个 item 读完后再读下一个 item。而使用并行去遍历时,数据会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出。Stream 的并行操作依赖于 Java7 中引入的 Fork/Join 框架(JSR166y)来拆分任务和加速处理过程。
甚至函数 由值创建流:
Stream<String> stream = Stream.of("Java 8 ", "Lambdas ", "In ", "Action");
由数组创建流:
int[] numbers = {2, 3, 5, 7, 11, 13}; int sum = Arrays.stream(numbers).sum();
用内部迭代取代外部迭代
外部迭代:描述怎么干,代码里嵌套2个以上的for循环的都比较难读懂;只能顺序处理List中的元素;
内部迭代:描述要干什么,而不是怎么干;不一定需要顺序处理List中的元素
List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
for (String feature : features) {
System.out.println(feature); //外部迭代
} List features = Arrays.asList("Lambdas", "Default Method", "Stream API",
"Date and Time API");
features.stream.forEach(n -> System.out.println(n)); //内部迭代
1.4 Lambda 中的 stream 效率
Lambda的并行流虽好,但也要注意使用场景。如果平常的业务处理比如过滤,提取数据,没有涉及特别大的数据和耗时操作,则真的不需要开启并行流。我在工作中看到有些人一个只有几十个元素的列表的过滤操作也开启了并行流,其实这样做会更慢。因为多行线程的开启和同步这些花费的时间往往比你真实的处理时间要多很多。但一些耗时的操作比如I/O访问,DB查询,远程调用,这些如果可以并行的话,则开启并行流是可提升很大性能的。因为并行流的底层原理是fork/join,如果你的数据分块不是很好切分,也不建议开启并行流。举个例子ArrayList的Stream可以开启并行流,而LinkedList则不建议,因为LinkedList每次做数据切分要遍历整个链表,这本身就已经很浪费性能,而ArrayList则不会。
有篇来自 发布在 jaxenter 的调查报告 《How misusing Streams can make your code 5 times slower》
原文地址点我进去 中文翻译版 点我进去 此文用代码实验得出了一个结论 如果你要进行stream操作 使用 iterators and for-each 效率更高
解问 lambda表达式的更多相关文章
- 【Java学习笔记之三十一】详解Java8 lambda表达式
Java 8 发布日期是2014年3月18日,这次开创性的发布在Java社区引发了不少讨论,并让大家感到激动.特性之一便是随同发布的lambda表达式,它将允许我们将行为传到函数里.在Java 8之前 ...
- java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口
函数式接口详细定义 函数式接口只有一个抽象方法 由于default方法有一个实现,所以他们不是抽象的. 如果一个接口定义了一个抽象方法,而他恰好覆盖了Object的public方法,仍旧不算做接口的抽 ...
- Lambda表达式常用代码示例
Lambda表达式常用代码示例 2017-10-24 目录 1 Lambda表达式是什么2 Lambda表达式语法3 函数式接口是什么 3.1 常用函数式接口4 Lambdas和Streams结合使 ...
- Java8特性详解 lambda表达式 Stream
1.lambda表达式 Java8最值得学习的特性就是Lambda表达式和Stream API,如果有python或者javascript的语言基础,对理解Lambda表达式有很大帮助,因为Java正 ...
- Lambda表达式详解(例子详解)(转自:http://blog.csdn.net/damon316/article/details/51734661)
Lambda表达式详解(例子详解) lambda简介 lambda运算符:所有的lambda表达式都是用新的lambda运算符 " => ",可以叫他,“转到”或者 ...
- lambda表达式,filter,map,reduce,curry,打包与解包和
当然是函数式那一套黑魔法啦,且听我细细道来. lambda表达式 也就是匿名函数. 用法:lambda 参数列表 : 返回值 例: +1函数 f=lambda x:x+1 max函数(条件语句的写法如 ...
- Python解包参数列表及 Lambda 表达式
解包参数列表 当参数已经在python列表或元组中但需要为需要单独位置参数的函数调用解包时,会发生相反的情况.例如,内置的 range() 函数需要单独的 start 和 stop 参数.如果它们不能 ...
- Java 8 Lambda 表达式详解
一.Java 8 Lambda 表达式了解 参考:Java 8 Lambda 表达式 | 菜鸟教程 1.1 介绍: Lambda 表达式,也可称为闭包,是推动 Java 8 发布的最重要新特性. La ...
- 类型:.net;问题:C#lambda表达式;结果:Lambda表达式详解
Lambda表达式详解 前言 1.天真热,程序员活着不易,星期天,也要顶着火辣辣的太阳,总结这些东西. 2.夸夸lambda吧:简化了匿名委托的使用,让你让代码更加简洁,优雅.据说它是微软自c#1 ...
随机推荐
- 网页实战开发笔记之——最全面的HTML的头部信息介绍
HTML中我们一般把<head></head>部分称为网页的头部.头部部分的内容虽然不会在页面中显示,但它能影响到搜索引擎对网页的收录和排序,以及网页的各种全局设置,可以说是至 ...
- 【BZOJ】2434: [Noi2011]阿狸的打字机 AC自动机+树状数组+DFS序
[题意]阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小写 ...
- CentOS 6 / RHEL 6配置bonding 4模式
实现bond 802.3ad or 4 模式:(IEEE 802.3ad), 方式:创建一个整合的组,这个组会共享网速和网络双工(duplex)设置.模式 4 会根据 IEEE 802.3ad 标准使 ...
- Django外键关系:一对一、一对多,多对多
1. 一对多 model.py class UserTest(models.Model): name = models.CharField(max_length = 16 ) sex = models ...
- JavaScript基本运算
JavaScript基本运算 JavaScript:其实它的基本运算和我们数学的基本运算类似的. --------------------------------------------------- ...
- JS设计模式——7.工厂模式(示例-XHR)
XHR工厂 基本实现 var AjaxHandler = new Interface('AjaxHandler', ['request', 'createXHR']); var SimpleHandl ...
- [转]使用 C++11 编写 Linux 多线程程序
前言 在这个多核时代,如何充分利用每个 CPU 内核是一个绕不开的话题,从需要为成千上万的用户同时提供服务的服务端应用程序,到需要同时打开十几个页面,每个页面都有几十上百个链接的 web 浏览器应用程 ...
- vue表格中显示金额格式化与保存时格式化为数字并校验!
最近项目中遇到了成本计算的,需要显示金额,保存一下,以后方便直接拿来用! 一 数字转金额格式显示 //数字转金额格式 format:function(s){ if(/[^0-9\.]/.test(s) ...
- ClientDataset 三层 var and out arguments must match parameter
将Delphi升级到10.1.2后,从客户端传ClientDataset的Delta数据到服务端程序时,出现var and out arguments must match parameter错 ...
- html5学习之canvas
Canvas画布 1.绘图方法 ctx.moveTo(x,y) 落笔ctx.lineTo(x,y) 连线ctx.stroke() 描边 ctx.beginPath(): 开启新的图层 演示: stro ...