lambda stream 循环_jdk8-lambda-stream的使用
1, 认识stream(声明式编程)
Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator, 原始版本的Iterator,用户只能一个一个的遍历元素并对其执行某些操作;高级版本的Stream,用户只要给出需要对其包含的元素执行什么操作,比如“过滤掉长度大于10的字符串”、“获取每个字符串的首字母”等,具体这些操作如何应用到每个元素上,就给Stream就好了!
Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返。依赖于 Java7 中引入的 Fork/Join 框架(JSR166y)来拆分任务和加速处理过程
2, 使用stream的基本过程
1, 创建Stream;
2, 转换Stream,每次转换原有Stream对象不改变,返回一个新的Stream对象(**可以有多次转换**);
3, 对Stream进行聚合(Reduce)操作,获取想要的结果;
3, 创建stream
1), 使用stream静态方法创建
@Test
public void test() {
// of
Stream integerStream = Stream.of(1, 2, 3, 5);
// generate, 无限长度, 懒加载, 类似工厂, 使用必须指定长度
Stream generate = Stream.generate(Math::random);
// iterator方法, 无限长度,
Stream.iterate(1, item -> item + 1).limit(10).forEach(System.out::print);
}
2), 通过collection的子类生成
Collection.stream()
Collection.parallelStream()
Arrays.stream(T array) or Stream.of()
@Testpublic voidtest2() {
List integers = Arrays.asList(1, 2, 3, 4, 5, 6);
Stream stream =integers.stream();
}
3), buffer生成 (通过实现 Supplier 接口)
java.io.BufferedReader.lines()
Pattern.splitAsStream(java.lang.CharSequence)
java.util.stream.IntStream.range()
4), 自定义supplier接口
@Testpublic voidtest13() {
Stream.generate(newPersonSupplier()).
limit(10).
forEach(p-> System.out.println(p.getName() + "," +p.getAge()));
}private class PersonSupplier implements Supplier{private int index = 0;private Random random = newRandom();
@Overridepublic Person get() {return new Person(index++, "StormTestUser" + index, random.nextInt(100));
}
}
流的主要操作( https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/index.html )
Intermediate:一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。
Terminal:一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。
分类操作
Intermediate:
map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered
Terminal:
forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator
Short-circuiting:
anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit
4, 转换stream
每次使用的本质, 是创建了一个新的stream, 旧的stream保持不变
1. distinct: 对于Stream中包含的元素进行去重操作(去重逻辑依赖元素的equals方法),新生成的Stream中没有重复的元素;2. filter: 对于Stream中包含的元素使用给定的过滤函数进行过滤操作,新生成的Stream只包含符合条件的元素;3. map: 对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素。
有 mapToInt, mapToLong, mapToDouble
直接转换为响应的类型, 避免拆装箱的消耗4. flatMap:和map类似,不同的是其每个元素转换得到的是Stream对象,会把子Stream中的元素压缩到父集合中;5. peek: 生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数(Consumer实例),新Stream每个元素被消费的时候都会执行给定的消费函数;6. limit: 对一个Stream进行截断操作,获取其前N个元素,如果原Stream中包含的元素个数小于N,那就获取其所有的元素;7. skip: 返回一个丢弃原Stream的前N个元素后剩下元素组成的新Stream,如果原Stream中包含的元素个数小于N,那么返回空Stream;
8. range: 截取
9, sorted: 排序
排序使用:
@Testpublic voidtest11() {
List list = Arrays.asList("2", "5", "2", "1", "8", "4", "3", "7", "9");
List list2 = list.stream().distinct().sorted((o1, o2) -> (Integer.parseInt(o2) -Integer.valueOf(o1))).collect(Collectors.toList());
System.out.println(list2);
}
综合:
@Testpublic voidtest3() {
List integers = Arrays.asList(1, 1, 3 , null, 2, null, 3, 4, 5, 8, 10);
System.out.println(integers.stream().filter(num -> num != null)
.distinct()
.mapToInt(num-> num * 10)
.peek(System.out::println).skip(2).limit(4).sum());
}
关于多次stream的性能问题:
转换操作都是lazy的,多个转换操作只会在汇聚操作(见下节)的时候融合起来,一次循环完成。我们可以这样简单的理解,Stream里有个操作函数的集合,每次转换操作就是把转换函数放入这个集合中,在汇聚操作的时候循环Stream对应的集合,然后对每个元素执行所有的函数。
流转换其他数据结构
//1. Array
String[] strArray1 = stream.toArray(String[]::new);//2. Collection
List list1 =stream.collect(Collectors.toList());
List list2 = stream.collect(Collectors.toCollection(ArrayList::new));
Set set1=stream.collect(Collectors.toSet());
Stack stack1= stream.collect(Collectors.toCollection(Stack::new));//3. String
String str = stream.collect(Collectors.joining()).toString();
5, 汇聚操作
汇聚操作(也称为折叠)接受一个元素序列为输入,反复使用某个合并操作,把序列中的元素合并成一个汇总的结果。比如查找一个数字列表的总和或者最大值,或者把这些数字累积成一个List对象。Stream接口有一些通用的汇聚操作,比如reduce()和collect();也有一些特定用途的汇聚操作,比如sum(),max()和count()
1), 可变汇聚, collect, 把输入的元素们累积到一个可变的容器中,比如Collection或者StringBuilder;
R collect(Suppliersupplier,accumulator, combiner);
Supplier supplier是一个工厂函数,用来生成一个新的容器;
BiConsumer accumulator也是一个函数,用来把Stream中的元素添加到结果容器中;
BiConsumer combiner还是一个函数,用来把中间状态的多个结果容器合并成为一个(并发的时候会用到)
@Testpublic voidtest4() {
List nums = Arrays.asList(1, 1, 3 , null, 2, null, 3, 4, 5, 8, 10);
List numsWithCollect = nums.stream().filter(num -> num != null)
.collect(()-> new ArrayList(),
(list, item)->list.add(item),
(list1, list2)->list1.addAll(list2));
System.out.println(numsWithCollect);
}
太繁琐了, 在jdk8 中提供了Collectors工具类, 可以直接实现汇聚( http://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html )
@Testpublic voidtest5() {
List nums = Arrays.asList(1, 1, 3 , null, 2, null, 3, 4, 5, 8, 10);
List collect = nums.stream().filter(num -> num != null)
.collect(Collectors.toList());
System.out.println(collect);
}
ps: collectos中提供了大量的方法, 粘贴一段api开头的方法
//Accumulate names into a List
List list =people.stream().map(Person::getName).collect(Collectors.toList());//Accumulate names into a TreeSet
Set set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));//Convert elements to strings and concatenate them, separated by commas
String joined =things.stream()
.map(Object::toString)
.collect(Collectors.joining(","));//Compute sum of salaries of employee
int total =employees.stream()
.collect(Collectors.summingInt(Employee::getSalary)));//Group employees by department
Map>byDept=employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment));//Compute sum of salaries by department
MaptotalByDept=employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment,
Collectors.summingInt(Employee::getSalary)));//Partition students into passing and failing
Map> passingFailing =students.stream()
.collect(Collectors.partitioningBy(s-> s.getGrade() >= PASS_THRESHOLD));
2) reduce汇聚
@Testpublic voidtest6() {
List nums = Arrays.asList(1, 1, 3 , null, 2, null, 3, 4, 5, 8, 10);
Integer count= nums.stream().filter(num -> num != null)
.reduce((sum, num)-> sum + num).get();
System.out.println(count);
}
可以看到reduce方法接受一个函数,这个函数有两个参数,第一个参数是上次函数执行的返回值(也称为中间结果),第二个参数是stream中的元素,这个函数把这两个值相加,得到的和会被赋值给下次执行这个函数的第一个参数。要注意的是:**第一次执行的时候第一个参数的值是Stream的第一个元素,第二个参数是Stream的第二个元素**。这个方法返回值类型是Optional,这是Java8防止出现NPE的一种可行方法,后面的文章会详细介绍,这里就简单的认为是一个容器,其中可能会包含0个或者1个对象。
可以提供一个初始值, 如果ints为空则直接返回默认值
List ints = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10);
System.out.println("ints sum is:" + ints.stream().reduce(0, (sum, item) -> sum + item));
count()
List ints = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10);
System.out.println("ints sum is:" + ints.stream().count());
match()
@Testpublic voidtest7() {
List nums = Arrays.asList(1, 1, 3 , null, 2, null, 3, 4, 5, 8, 10);
System.out.println(nums.stream().filter(num -> num != null).allMatch(num -> num < 8));
}
max(), min()
@Testpublic voidtest12() throws IOException {
BufferedReader br= new BufferedReader(new FileReader("d:\\test.log"));int longest =br.lines().
mapToInt(String::length).
max().
getAsInt();
br.close();
System.out.println(longest);
}
– allMatch:是不是Stream中的所有元素都满足给定的匹配条件
– anyMatch:Stream中是否存在任何一个元素满足匹配条件
- noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true
– findFirst: 返回Stream中的第一个元素,如果Stream为空,返回空Optional
– noneMatch:是不是Stream中的所有元素都不满足给定的匹配条件
– max和min:使用给定的比较器(Operator),返回Stream中的最大|
3) 分组
按年龄分组
@Testpublic voidtest13() {
Map> personGroups = Stream.generate(newPersonSupplier()).
limit(100).
collect(Collectors.groupingBy(Person::getAge));
Iterator it=personGroups.entrySet().iterator();while(it.hasNext()) {
Map.Entry> persons =(Map.Entry) it.next();
System.out.println("Age" + persons.getKey() + "=" +persons.getValue().size());
}
}
按是否成年分组
@Test
public void test13() {
Map> children = Stream.generate(new PersonSupplier()).
limit(100).
collect(Collectors.partitioningBy(p -> p.getAge() < 18));
System.out.println("Children number: " + children.get(true).size());
System.out.println("Adult number: " + children.get(false).size());
}
一个综合运用的例子:
MongoClient client =getMongoClient();
MongoDatabase mongoDatabase=client.getDatabase(Constance.database());
MongoCollection collection =mongoDatabase.getCollection(Constance.collection());
MongoIterable iter = collection.find().map(document ->{
String topic= document.get("topic").toString().toUpperCase();
String mac= document.get("mac").toString().toUpperCase();return newTopicMacEntity(topic, mac);
});
Map> collect =Lists.newArrayList(iter).stream().collect(Collectors.groupingBy(TopicMacEntity::topic));
Map> resultMap =collect.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, v-> v.getValue().stream().map(t ->t.mac()).collect(Collectors.toList())));return resultMap;
更多grouping的强大用法:
http://developer.51cto.com/art/201404/435431.htm
原博客:
http://ifeve.com/stream/
lambda stream 循环_jdk8-lambda-stream的使用相关推荐
- 当你的Stream遇上Lambda就爱上了,超级无敌酷酷 - 第418篇
历史文章(累计400+篇文章) <国内最全的Spring Boot系列之一> <国内最全的Spring Boot系列之二> <国内最全的Spring Boot系列之三&g ...
- Java8新特性概览——Stream特性,Lambda表达式,函数式接口Function、Predicate、Consumer,方法引用等概述
概述: Java 8 新特性概述:https://www.ibm.com/developerworks/cn/java/j-lo-jdk8newfeature/index.html JAVA8 十大新 ...
- Stream流与Lambda表达式(一) 杂谈
一.流 转换为数组.集合 package com.java.design.java8.Stream;import org.junit.Test; import org.junit.runner.Run ...
- 使用Java8新特性(stream流、Lambda表达式)实现多个List 的笛卡尔乘积 返回需要的List<JavaBean>
需求分析: 有两个Long类型的集合 : List<Long> tagsIds; List<Long> attributesIds; 现在需要将这两个Long类型的集合进行组合 ...
- 【Java从入门到头秃专栏 7】语法篇(六) :Lambda表达式(->) 方法引用(::) stream流
目录 1 Lambda表达式( -> ) 2 方法引用( :: ) 3 Stream流 接下来介绍的三种语法叫:Lambda表达式 方法引用 stream流,这三种语法的使用要有特定条件,在 ...
- comparator接口_8000字长文让你彻底了解 Java 8 的 Lambda、函数式接口、Stream 用法和原理
我是风筝,公众号「古时的风筝」.一个兼具深度与广度的程序员鼓励师,一个本打算写诗却写起了代码的田园码农! 文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白到大牛要走的路都在 ...
- Lambda、函数式接口、Stream 一次性全给你
就在今年 Java 25周岁了,可能比在座的各位中的一些少年年龄还大,但令人遗憾的是,竟然没有我大,不禁感叹,Java 还是太小了.(难道我会说是因为我老了?) 而就在上个月,Java 15 的试验版 ...
- 函数式编程(Lambda表达式、Optional、Stream流)
函数式编程(Lambda表达式.Optional.Stream流) 文章目录 函数式编程(Lambda表达式.Optional.Stream流) 一.概述 1. 为什么要学习函数式编程? 2. 函数式 ...
- 10000字长文让你了解 Java 8 Lambda、函数式接口、Stream 用法和原理
一定要看到最后,那是心动的感觉! 我是风筝,公众号「古时的风筝」.一个兼具深度与广度的程序员鼓励师,一个本打算写诗却写起了代码的田园码农!文章会收录在 JavaNewBee 中,更有 Java 后端知 ...
最新文章
- Squid故障与解决方法汇总
- 在用安全框架前,我想先让你手撸一个登陆认证
- 史上最详细版Centos6安装详细教程
- java达达租车接口_Java第一个项目——达达租车系统v1
- Windows2008应用之配置客户端自动添加打印机
- Maven——继承和聚合
- kettle创建mysql资源库
- 17 - 引用类型比较内容
- free bsd x修改UTC-SCT
- FineReport帆软学习笔记汇总
- Java八大基础数据类型转换
- CVE-2018-5767 栈溢出漏洞复现
- 国内的9家域名顶级注册商
- 剑心---速度与位置
- 如何安装java环境_如何安装java环境变量
- js判断两个时间是否超过一年
- 【网络游戏植入案例】
- 用python让excel飞起来(第7章 图表操作)
- js之 实现浏览器下载图片保存到本地
- linux解压7z文件,Linux下解压.zip.7z和.rar文件
热门文章
- nodeName,nodeValue,nodeType,typeof,instanceof 的区别
- java基类和派生类圆_java – 当基类和派生类都具有相同名称的变量时会发生什么...
- 怎么把git代码导入到本地仓库_git在本地仓库添加了一个tag,如何把这个tag同步到远程仓库?...
- android 支付宝 地图,利用百度地图实现支付宝“到位”功能(地图模式)
- 零基础学习java------day1------计算机基础以及java的一些简单了解
- JavaScript 数据类型梳理
- 软件测试 第三次作业
- Java中正则表达式、模式匹配与信息抽取
- 学习Altas 笔记[js调用重载的方法出错,如何处理]
- java插件安装步骤_eclipse插件安装的四种方法