1.3 Lambda中的streamhtml
所谓 “Lambda 表达式”(lambda expression)它是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Lambda表达式能够表示闭包(注意和数学传统意义上的不一样)。若是想深刻能够去这位仁兄的博客看看 点我进去 这里作个了解。java
认准 " - > " Lambad 老字号算法
可选类型声明:不须要声明参数类型,编译器能够统一识别参数值。 express
可选的参数圆括号:一个参数无需定义圆括号,但多个参数须要定义圆括号。数组
可选的大括号:若是主体包含了一个语句,就不须要使用大括号。 数据结构
可选的返回关键字:若是主体只有一个表达式返回值则编译器会自动返回值,大括号须要指定明表达式返回了一个数值。闭包
在 Lambda 表达式当中不容许声明一个与局部变量同名的参数或者局部变量。框架
String first = "";
Comparator<String> comparator = (first, second) -> Integer.compare(first.length(), second.length()); //编译会出错
从语法特征分析出的傻白甜代码片断 ide
// 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
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());//复合操做
在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)); //内部迭代
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 效率更高