Java--8--新特性--Stream API
Stream API 提供了一种高效且易于使用的处理数据的方式,(java.util.stream.*)
他可以对数组,集合等做一些操作,最终产生一个新的流,原数据是不会发生改变的。
“集合”讲的是数据,“流”讲的是计算!
注意:
1. Stream自己不会储存元素
2. 不会改变源对象,相反,它会产生一个新的Stream
3. 操作是延迟执行的,这意味着他们会等到需要结果的时候才执行
package StreamP;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream; public class Stream1 {
/**
* Stream 操作三步骤
* 1. 创建Stream
* 2. 中间操作
* 3. 终止操作
*/
//创建Stream
public void test(){
//可以通过Collection系列集合的 stream()方法 或 parallelStream()创建流
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream(); //可以通过Arrays中的静态方法 stream() 得到一个数组流
Integer[] integers = new Integer[2];
Stream<Integer> stream1 = Arrays.stream(integers); //通过Stream中的of()方法
Stream<String> stringStream = Stream.of("a", "b"); //创建无限流
//迭代 第一个参数其实就是一个起始值,第二个参数是一个接口,代表一元运算
Stream<Integer> stream2 = Stream.iterate(0,(x)->x+2);
//生成 需要的是一个供给型接口
Stream<Double> generate = Stream.generate(() -> Math.random());
generate.limit(5).forEach(System.out::println);
// 0.9108574640882595
// 0.8772485678436105
// 0.00318519741701917
// 0.3682731233198696
// 0.39645909717553074
}
}
下面是Stream 的中间操作的一些方法
筛选与切片测试代码
package StreamP; import LambdaP.Employee;
import org.junit.Test;
import java.util.Arrays;
import java.util.List; public class Stream2 { //中间操作:多个中间操作可以连接起来形成一个流水线,除非触发终止操作,否则中间操作不会执行任何处理!而在终止操作时一次性全部处理,称为惰性求值
/**
* 筛选与切片
* filter-接收Lambda,从流中排除某些元素
* limit-截断流,使元素不超过给定数量
* slip(n)-跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流,与limit互补
* distinct-筛选,通过流所生成元素的hashCode(),equals()去除重复元素
*/
public static List<Employee> employees = Arrays.asList(
new Employee("张三", 19, 2000),
new Employee("张四", 33, 3000),
new Employee("张五", 38, 4000),
new Employee("张六", 41, 2500),
new Employee("张七", 42, 5500),
new Employee("张七", 42, 5500),
new Employee("张七", 42, 5500)
);
public void test(){
employees.stream().filter((x) -> x.getage()==19).forEach(System.out::println);
//Employee{name='张三', age=19, salary=2000} 意思就是遍历集合取出每一个对象,如果对象中的Age等于19,那么他就会通过filter
}
public void test1(){
employees.stream().filter((x) ->x.getage()<42).limit(2).forEach(System.out::println);
//Employee{name='张三', age=19, salary=2000} 意思就是取出age<42的前两个对象 limit跟数据库的limit基本一样
//Employee{name='张四', age=33, salary=3000} 注意这里的limit,如果找到指定数量的数据后,循环迭代就自己结束了,不会一直遍历
}
public void test2(){
employees.stream().filter((x)->x.getage()<42).skip(2).forEach(System.out::println);
//LambdaP.Employee{name='张五', age=38, salary=4000}
//LambdaP.Employee{name='张六', age=41, salary=2500}
//意思就是跳过前两个,输出满足条件的其他对象数据
}
@Test
public void test3(){
//到这一步才新添加的重复的“张七”,以上的操作时没有重复元素的
employees.stream().distinct().forEach(System.out::println);
//去重操作!注意!!!!!必须重写去重目标对象中的hashCode与equals方法!
}
}
映射的操作代码
package StreamP; import LambdaP.Employee;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream; public class Stream3 {
/**
* 中间操作‘
* 映射
* map-接收Lambda,将元素转换成其他形式或提取信息。接受一个函数作为参数,该函数会被应用到每个元素上,并将 其映射成一个新的元素。
* flatMap-接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
*/
public static List<Employee> employees = Arrays.asList(
new Employee("张三", 19, 2000),
new Employee("张四", 33, 3000),
new Employee("张五", 38, 4000),
new Employee("张六", 41, 2500),
new Employee("张七", 42, 5500),
new Employee("张七", 42, 5500),
new Employee("张七", 42, 5500)
); public void test(){
//所有变大写
List<String> list = Arrays.asList("a","b","c","d","e");
list.stream()
.map((x) -> x.toUpperCase())//需要一个Function接口
.forEach(System.out::println);
System.out.println("**************************************");
//取出所有的Name
employees.stream().map(Employee::getName).distinct().forEach(System.out::println);
/**
* map他会将流中的每一个元素都应用到map后的表达式上!
*/
} //需求:把每个字母都转换成char
public void test1(){
List<String> list = Arrays.asList("aaa","bbb","ccc","ddd","eee");
Stream<Character> aChar = getChar(list);
aChar.forEach(System.out::println);
}
public static Stream<Character> getChar(List<String> list){
List<Character> lists = new ArrayList<>();
//遍历传入的list,现在的lambda中的e为"aaa","bbb","ccc","ddd","eee"
list.stream().forEach((e)->{
char[] ch = e.toCharArray();
for (char c : ch) {
lists.add(c);
}
});
return lists.stream();
}
//需求:把每个字母都转换成char
public void test2(){
List<String> list = Arrays.asList("aaa","bbb","ccc","ddd","eee");
//这里的返回是一个流套流,因为map本身会返回一个流,并且调用的方法也返回来一个流
Stream<Stream<Character>> streamStream = list.stream().map(Stream3::getchar);
//外层的流
streamStream.forEach((e) -> {
//传入的e 为内层流
e.forEach((r) -> {
System.out.println(r);
});
});
}
public static Stream<Character> getchar(String string){
List<Character> list = new ArrayList<>();
char[] chars = string.toCharArray();
for (char aChar : chars) {
list.add(aChar);
}
return list.stream();
}
//这时候我们就可以看到map方法对于这种操作的已经有一些麻烦了
//这时候我们可以考虑使用flatMap,
@Test
public void test3(){
List<String> list = Arrays.asList("aaa","bbb","ccc","ddd","eee");
list.stream().flatMap(Stream3::getchar).forEach(System.out::println);
//结果是与上面是一样一样的
}
/**
* map 与 flatMap 的区别
* map是把每个源数据中的每个元素进行操作,map是一个大的流,那么每个元素就是一个个的小流,map是把每个小流加入到大流中
* {{a,a,a},{b,b,b},{c,c,c}}
* flatMap是把源数据中的每个元素中的子元素进行操作,flatMap是一个大流,那么他会把每个子元素加入自己的大流中
* {a,a,a,b,b,b,c,c,c}
*
* map 就类似与List中的add(Object obj)方法,
* flatMap就类似List中的 addAll(Collection con)方法
*/ }
排序
package StreamP; import LambdaP.Employee;
import org.junit.Test; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; public class Stream4 {
/**
* 排序
* sorted()-自然排序(Comparable)
* sorted(Comparator com)-定制排序
*/ public static List<Employee> employees = Arrays.asList(
new Employee("张三", 19, 2000),
new Employee("张四", 33, 3000),
new Employee("张五", 38, 4000),
new Employee("张六", 41, 2500),
new Employee("张六", 41, 1500),
new Employee("张七", 42, 5500)
);
//自然排序
public void test(){
List<String> list = Arrays.asList("a","c","r","d","b","z","1");
list.stream().sorted().forEach(System.out::print);//1abcdrz
}
//利用上面集合排序,按名字排序,名字相同按工资排序
@Test
public void test1(){
employees.stream().sorted((x,y)->{
if(x.getName().equals(y.getName())){
return Integer.compare(x.getSalary(),y.getSalary());
}else {
return x.getName().compareTo(y.getName());
}
}).forEach(System.out::println);
// LambdaP.Employee{name='张七', age=42, salary=5500}
// LambdaP.Employee{name='张三', age=19, salary=2000}
// LambdaP.Employee{name='张五', age=38, salary=4000}
// LambdaP.Employee{name='张六', age=41, salary=1500}
// LambdaP.Employee{name='张六', age=41, salary=2500}
// LambdaP.Employee{name='张四', age=33, salary=3000}
}
}
查找与匹配
package StreamP; import LambdaP.Employee;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import java.util.Optional; public class Stream5 {
public static List<Employee> employees = Arrays.asList(
new Employee("张四", 33, 3000),
new Employee("张五", 38, 4000),
new Employee("张六", 41, 2500),
new Employee("张三", 19, 2000),
new Employee("张六", 41, 1500),
new Employee("张七", 42, 5500)
);
/**
* 查找与匹配
* allMatch-检查是否匹配所有元素
* anyMatch-检查是否匹配至少一个元素
* noneMatch-检查是否没有匹配所有元素
* findFirst-返回第一个元素
* findAny-返回当前流中的任意元素
* count-返回流中总个数
* max-返回流中最大值
* min-返回流中最小值
*/
//allMatch测试
public void test(){
boolean b = employees.stream().allMatch((e) -> e.getName().getClass()==String .class);
System.out.println(b);//true 检查名字是不是String类型的,那肯定是啊
boolean b1 = employees.stream().allMatch((e)->e.getSalary()==1500);
System.out.println(b1);//false 检查工资是否都等于1500,那肯定不是啊
}
//anyMatch测试
public void test1(){
boolean zhang = employees.stream().anyMatch((e) -> e.getName().equals("张三"));
System.out.println(zhang);//检查是否有一个匹配张三的 true
}
//noneMatch测试
public void test2(){
boolean b = employees.stream().noneMatch((e) -> e.getSalary() == 1500);
System.out.println(b);//false 检查是否没有匹配所有元素,如果判断条件存在于流中那么他就返回false,如果不存在那么就返回true
}
//findFirst测试
public void test3(){
//Optional 是java 8 中新增的,为了防止空指针异常,别的帖子会解释这个类
Optional<Employee> first = employees.stream().findFirst();
System.out.println(first.get());//LambdaP.Employee{name='张三', age=19, salary=2000}
}
//findAny测试
public void test4(){
//这里Strem串行流 与 parallelStream并行流 的区别
//Stream时一条线程去找,并行流即几条线程同时去找,谁找到算谁的
Optional<Employee> any = employees.parallelStream().findAny();
System.out.println(any);
}
//count测试
public void test5(){
long count = employees.stream().count();
System.out.println(count);//
}
//max测试
public void test6(){
//max与min都必须有比较条件才可以
Optional<Employee> max = employees.stream().max((e1, e2) -> Integer.compare(e1.getSalary(), e2.getSalary()));
System.out.println(max.get());//LambdaP.Employee{name='张七', age=42, salary=5500}
}
//min测试
@Test
public void test7(){
Optional<Employee> min = employees.stream().min((e1, e2) -> Integer.compare(e1.getage(), e2.getage()));
System.out.println(min.get());//LambdaP.Employee{name='张三', age=19, salary=2000}
}
}
归约
package StreamP; import LambdaP.Employee;
import java.util.Arrays;
import java.util.List;
import java.util.Optional; public class Stream6 {
/**
* 归约
* reduce(T identity,BinaryOperator) / reduce(BinaryOperator)--可以将流中的元素反腐结合起来,得到一个值。
*/
public static List<Employee> employees = Arrays.asList(
new Employee("张四", 33, 3000),
new Employee("张五", 38, 4000),
new Employee("张六", 41, 2500),
new Employee("张三", 19, 2000),
new Employee("张六", 41, 1500),
new Employee("张七", 42, 5500)
);
public void test(){
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
//求和
Integer reduce = list.stream().reduce(0, (x, y) -> x + y);
System.out.println(reduce);//
/**
* reduce第一个参数是一个起始值,第二个参数是一个二元运算,
* 这个方法有重载,像上面这个方法的话,
* 他每次把值都放到y,第一次x起始值为0,所以就是0+y,0+y的结果再次放到x,然后把下一个元素放到y,在进行运算,以此类推
*/
}
public void test1(){
//获取工资总和、
//获取employees的流,然后取出每个对象的工资,然后求和
Integer reduce = employees.stream().map(Employee::getSalary).reduce(0, (x, y) -> x + y);
System.out.println(reduce);//18500
//***********************************************************************
//sum 定义如下 public static int sum(int a, int b) {
// return a + b;
// }
Optional<Integer> reduce1 = employees.stream().map(Employee::getSalary).reduce(Integer::sum);
System.out.println(reduce1.get());//18500这里为啥是返回Optional?因为上一个重载的reduce有起始值,再怎么滴都是有值的,那么这个是没有起始值保证的
}
}
收集:!!!!!!!
package StreamP; import LambdaP.Employee;
import org.junit.Test;
import java.util.*;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors; public class Stream7 {
/**
* 收集:
* collect--将流转换为其他形式,接收一个Collector(收集器)接口的实现,用于给Stream中元素做汇总的方法
* 在这里,java为我们提供了Collector接口的工具类 Collectors实现类,里面有很多静态方法可供调用
*/
public static List<Employee> employees = Arrays.asList(
new Employee("张四", 33, 3000),
new Employee("张五", 38, 4000),
new Employee("张六", 41, 3000),
new Employee("张三", 19, 2000),
new Employee("张7", 41, 3000),
new Employee("张七", 42, 5500)
);
//收集到指定集合中!
public void test(){
//需求 ,将名字提取出来,放到List中咋办呢
List<Employee> collect = employees.stream().collect(Collectors.toList());
collect.stream().forEach(System.out::println);//即可输出
System.out.println("***************");
//如果平时我们需要的收集到的集合没有提供相应的办法咋办
HashSet<Employee> collect1 = employees.stream().collect(Collectors.toCollection(HashSet::new));
for (Employee employee : collect1) {
System.out.println(employee);
}
}
//可以计算各项数据
public void test1(){
//求总数
Long collect = employees.stream().collect(Collectors.counting());
System.out.println(collect);//6
//求最小
Optional<Employee> collect1 = employees.stream().collect(Collectors.minBy((x, y) -> Integer.compare(x.getSalary(), y.getSalary())));
System.out.println(collect1.get());//LambdaP.Employee{name='张六', age=41, salary=1500} System.out.println("*************************");
//取出工资求工资最小
Optional<Integer> collect2 = employees.stream().map(Employee::getSalary).collect(Collectors.minBy(Integer::compare));
System.out.println(collect2.get());//1500
//求最大
Optional<Employee> collect3 = employees.stream().collect(Collectors.maxBy((x, y) -> x.getage() - y.getage()));
System.out.println(collect3);//Optional[LambdaP.Employee{name='张七', age=42, salary=5500}]以为没有get,所以外层抱着一个Optional对象
//求平均
Double collect4 = employees.stream().collect(Collectors.averagingInt(Employee::getSalary));
System.out.println(collect4);//3083.3333333333335 这里平均数有三个不同的方法分别是转int,转double,转long,并且后面时自己循环,不需要自己map了
//求和 同样是三个不同方法 转int,转double,转long
Double collect6 = employees.stream().collect(Collectors.summingDouble(Employee::getage));
System.out.println(collect6);//214.0
// 同样是三个不同方法 转int,转double,转long,但是这里是按照 指定列 把上面的所有参数都求出来的
DoubleSummaryStatistics collect5 = employees.stream().collect(Collectors.summarizingDouble(Employee::getage));
System.out.println(collect5);//DoubleSummaryStatistics{count=6, sum=214.000000, min=19.000000, average=35.666667, max=42.000000}
System.out.println(collect5.getCount());//
System.out.println(collect5.getMax());//42。0
}
//分组!!
public void test2(){
//在这我才更改了上面集合的工资数据,
Map<Integer, List<Employee>> collect = employees.stream().collect(Collectors.groupingBy(Employee::getSalary));
System.out.println(collect);//下面的数据就是分组后的,Map的key为分组条件,value为List的分组后的对象
//{
// 2000=[LambdaP.Employee{name='张三', age=19, salary=2000}, LambdaP.Employee{name='张六', age=41, salary=2000}],
// 4000=[LambdaP.Employee{name='张五', age=38, salary=4000}],
// 3000=[LambdaP.Employee{name='张四', age=33, salary=3000}, LambdaP.Employee{name='张六', age=41, salary=3000}],
// 5500=[LambdaP.Employee{name='张七', age=42, salary=5500}]
// } ConcurrentMap<Integer, List<Employee>> collect1 = employees.stream().collect(Collectors.groupingByConcurrent(Employee::getSalary));
System.out.println(collect1);//还没搞清。。。。
//{
// 4000=[LambdaP.Employee{name='张五', age=38, salary=4000}],
// 2000=[LambdaP.Employee{name='张三', age=19, salary=2000}, LambdaP.Employee{name='张六', age=41, salary=2000}],
// 3000=[LambdaP.Employee{name='张四', age=33, salary=3000}, LambdaP.Employee{name='张六', age=41, salary=3000}],
// 5500=[LambdaP.Employee{name='张七', age=42, salary=5500}]
//}
}
//多级分组!!
public void test3(){
//按工资分,工资一样按年龄分
Map<Integer, Map<String, List<Employee>>> collect = employees.stream().collect(Collectors.groupingBy(Employee::getSalary, Collectors.groupingBy((e) -> {
if (e.getage() < 20) {
return "青年";
} else if (e.getage() < 40) {
return "中年";
} else {
return "老年";
}
})));
System.out.println(collect);
//{
// 2000={青年=[LambdaP.Employee{name='张三', age=19, salary=2000}]},
// 4000={中年=[LambdaP.Employee{name='张五', age=38, salary=4000}]},
// 3000={老年=[LambdaP.Employee{name='张六', age=41, salary=3000}, LambdaP.Employee{name='张7', age=41, salary=3000}], 中年=[LambdaP.Employee{name='张四', age=33, salary=3000}]},
// 5500={老年=[LambdaP.Employee{name='张七', age=42, salary=5500}]}
//}
}
//分区 分为true与false
public void test4(){
Map<Boolean, List<Employee>> collect = employees.stream().collect(Collectors.partitioningBy((e) -> e.getage() > 35));
System.out.println(collect);
//{
// false=[LambdaP.Employee{name='张四', age=33, salary=3000}, LambdaP.Employee{name='张三', age=19, salary=2000}],
// true=[LambdaP.Employee{name='张五', age=38, salary=4000}, LambdaP.Employee{name='张六', age=41, salary=3000},
// LambdaP.Employee{name='张7', age=41, salary=3000}, LambdaP.Employee{name='张七', age=42, salary=5500}]
//}
}
//连接!
@Test
public void test5(){
//参数:第一个是用什么隔开这些需要连接的字符串,第二个是字符串开头,第三个是字符串结尾
String collect = employees.stream().map(Employee::getName).collect(Collectors.joining(",", "--", "--"));
System.out.println("collect = " + collect);//collect = --张四,张五,张六,张三,张7,张七--
}
}
Stream API就到此结束了!
Java--8--新特性--Stream API的更多相关文章
- Java 8新特性--Stream API
Java 8 API添加了一个新的抽象称为流Stream,以一种声明的方式处理数据,可以极大提高程序员的生产力,写出高效.干净.简洁的代码.这种风格将要处理的元素集合看作一种流,流在管道中传输,并且可 ...
- JDK1.8新特性——Stream API
JDK1.8新特性——Stream API 摘要:本文主要学习了JDK1.8的新特性中有关Stream API的使用. 部分内容来自以下博客: https://blog.csdn.net/icarus ...
- Java8 新特性 Stream() API
新特性里面为什么要加入流Steam() 集合是Java中使用最多的API,几乎每一个Java程序都会制造和处理集合.集合对于很多程序都是必须的,但是如果一个集合进行,分组,排序,筛选,过滤...这些操 ...
- Java 8 新特性-Stream更优雅的处理集合入门
Java 8 新特性之--Stream 一. 简单介绍 Stream是Java 8提出了的一种新的对集合对象功能的增强.它集合Lambda表达式,对集合提供了一些非常便利,高效的操作,使得代码具有非常 ...
- 再来看看Java的新特性——Stream流
半年前开始试着使用Java的新特性,给我印象最深的就是Stream流和Optional.其中Stream提高了看法效率,让代码看起来十分清爽. 为什么要使用流? 摘要中已经说明了,为了提高开发效率.流 ...
- Java 8 新特性---------Stream
Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据. Stream使用一种类似用SQL语句从数据库查询数据的直观方式来提供一种对Java集合运算和表达的高阶抽象 ...
- java8新特性——Stream API
Java8中有两大最为重要得改变,其一时Lambda表达式,另外就是 Stream API了.在前面几篇中简单学习了Lambda表达式得语法,以及函数式接口.本文就来简单学习一下Stream API( ...
- Java8 新特性 Stream Api 之集合遍历
前言 随着java版本的不断更新迭代,java开发也可以变得甜甜的,最新版本都到java11了,但是后面版本也是不在提供商用支持,需要收费,但是java8 依然是持续免费更新使用的,后面版本也更新很快 ...
- Java8新特性 - Stream API
Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找.过滤和映射数据等操作.使用Stream API对集合进行操作,就类似与使用SQL执行的数据库 ...
- JAVA 8 新特性Stream初体验
什么是 Stream? Stream(流)是一个来自数据源的元素队列并支持聚合操作 <strong元素队列< strong="">元素是特定类型的对象,形成一个队 ...
随机推荐
- 在Spring+MyBatis组合中使用事务
通过Spring和MyBatis的组合,给出一个较为详细的实例 代码清单:配置Spring+MyBatis测试环境 <?xml version='1.0' encoding='UTF-8' ? ...
- Find minimum number of people to reach to spread a message across all people in twitter
Considering that I'ld would like to spread a promotion message across all people in twitter. Assumin ...
- SpringMVC:学习笔记(11)——依赖注入与@Autowired
SpringMVC:学习笔记(11)——依赖注入与@Autowired 使用@Autowired 从Spring2.5开始,它引入了一种全新的依赖注入方式,即通过@Autowired注解.这个注解允许 ...
- MangoDB
<MongoDB权威指南> 一.简介 MongoDB是一款强大.灵活.且易于扩展的通用型数据库 1.易用性 MongoDB是一个面向文档(document-oriented)的数据库,而不 ...
- Node.js安装windows环境
一.安装环境 1.本机系统:Windows 10 Pro(64位)2.Node.js:v6.9.2LTS(64位) 二.安装Node.js步骤 1.下载对应你系统的Node.js版本:https:// ...
- 开始使用 Manjaro(添加源+字体渲染去模糊+软件安装+优化配置+常见错误)(30)
1. 添加 archlinux 镜像源 1. 步骤一 向 /etc/pacman.d/mirrorlist 中添加国内镜像地址 1.1 方法1:自动添加 1. 输入如下命令查看国内镜像源,并按质量排序 ...
- Mysql之rpm安装5.7版本遇见的问题
前言:环境是centos7.5的系统,用rpm方式安装mysql5.7 1.由于是centos7.5 所以需要将默认的mariadb给卸载 rpm -qa | grep mariadb 查看下是否有m ...
- unittest之makeSuite\testload\discover及测试报告teseReport
转载:http://www.cnblogs.com/sunny0/p/7771089.html 测试套件suite除了使用addTest以外,还有使用操作起来更更简便的makeSuite\testlo ...
- Jmeter之分布式测试/压测
Jmeter做分布式测试的原因: 测试机器的配置低,对服务器进行压测时,造成不了压力. jmeter并发10000后,测试机就已经卡顿了,而且测试结果有大量失败(忽略了jmeter自身问题=.=||| ...
- 游记-NOI2019
Day -18 被各路julao们轮番吊打-- Day -12 鸽子F发布了笔试题库,然而并没有 "MLE全场记零分" 的操作 Day -8 广二体育馆机器装配完毕,误闯开幕式表演 ...