简介stream和stream api
stream是java8中处理集合的关键抽象概念,它可以指定你对集合进行的操作,可以进行非常复杂的查找、过滤和映射数据等操作。使用stream api 对集合数据进行操作,就类似于使用sql执行数据库 查询。也可以使用stream api来并行执行操作。简而言之,stream api 提供了一种高效且易于使用的处理数据的方式。
它和stream(流)不是一个概念:什么是流?是数据渠道,用于操作数据源(集合或者数组)所生成的元素序列。 集合讲的是数据,流讲的是计算。
注意:
1.stream自己不会存储元素。
2.stream不会改变源对象。相反 他们会返回一个持有结果的新stream。
3.stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
stream操作的三个步骤
1.创建stream:通过数据源获取一个流 ;
2.中间操作:一个中间操作链,对数据源的数据进行处理;
3.终止操作:一个终止操作,执行中间操作链,并产生结果。
一、创建stream
创建方式代码中注释给了
public void test7(){
//创建stream
//1.可以通过Collection系列集合提供的stream()或parallelStream()
List<String> list=new ArrayList<>();
Stream<String> stream = list.stream();
//2.可以通过Arrays中的静态方法stream()获取数组流
People[] people=new People[10];
Stream<People> stream1 = Arrays.stream(people);
//3.通过stream类中的静态方法 of()
//public static<T> Stream<T> of(T... values)
Stream<String> stringStream = Stream.of("11", "22", "33");
//4.创建无限流
//(1)迭代
//public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
//seed 就相当于起始值,按照一元运算的规律产生一个无限流
Stream<Integer> iterate = Stream.iterate(0, x -> x + 2);
//(2)生成
Stream<Double> generate = Stream.generate(() -> Math.random());
}
二、中间操作
先定义一个集合:
//中间操作
List<People> peopleList = Arrays.asList(new People("黛玉",14,'女',1),
new People("宝玉",16,'男',1),
new People("宝钗",14,'女',1),
new People("贾政",30,'男',1),
new People("贾政",30,'男',2),
new People("元春",18,'女',1)
);
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!!而在终止操作时一次性全部处理,称为“惰性求值”。
注::中间操作不能产生结果,只有终止操作才能产生结果。
筛选和切片:
filter: 接收lambda,从流中排除某些元素
limit: 截断流,使其元素不超过指定数量
skip(n): 跳过元素,返回一个扔掉了前n个元素的流,若流中的元素不足n个,则返回一个空的流
distinct: 筛选,通过流中的hashcode()和equals()去除重复元素
@Test
public void test8(){
//返回一个年龄大于15的新流
Stream<People> peopleStream = peopleList.stream()
.filter(a -> a.getAge() > 15);
// 终止操作检验一下
peopleStream.forEach(System.out::println);
}
@Test
public void test9(){
//返回一个年龄大于15的流,只保留前两位
Stream<People> limitStream = peopleList.stream()
.filter(a -> a.getAge() > 15)
.limit(2);
//检验结果
limitStream.forEach(System.out::println);
}
@Test
public void test10(){
//返回一个跳过前两个元素的新流
Stream<People> skipStream = peopleList.stream()
.filter(a -> a.getAge() > 15)
.skip(2);
//检验结果
skipStream.forEach(System.out::println);
}
@Test
public void test11(){
//返回一个去除重复元素的流(这个使用的前提是:javaBean中重写了.equals()和.hashCode()这两个方法)
Stream<People> distinctStream = peopleList.stream()
.filter(a -> a.getAge() > 15)
.distinct();
//检验结果
distinctStream.forEach(System.out::println);
}
映射:
map-接收lambda,将元素转换成其他形式或者提取信息。接收一个函数作为参数,该函数会用到每个元素上
并将其映射成一个新的元素。
flatmap-接收一个函数作为参数,将流中的每一个值都替换成另一个流,然后把所有的流连成一个新的流。
//映射 map/flatmap
@Test
public void test12(){
List<String> list = Arrays.asList("aaa", "bbb", "ccc");
//全部大写
list.stream()
.map(a->a.toUpperCase())
.forEach(System.out::println);
//找出年龄大于15 的所有年龄
peopleList.stream()
.map(People::getAge)
.filter(a->a>15)
.forEach(System.out::println);
//map 与 flatmap之间的区别是
Stream<Stream<Character>> streamStream = list.stream()
.map(StreamApiTest::change);
streamStream.forEach(a->{
a.forEach(System.out::print);
});//{ {a,a,a},{b,b,b},{c,c,c} }
System.out.println("````````````````````````````````````````````````");
Stream<Character> characterStream = list.stream()
.flatMap(StreamApiTest::change);
characterStream.forEach(System.out::print);//{ a,a,a,b,b,b,c,c,c }
}
//定义一个方法 把字符串转换成字节流
public static Stream<Character> change(String string){
List list=new ArrayList();
for (char c : string.toCharArray()) {
list.add(c);
}
return list.stream();
}
排序:
sorted():自然排序
sorted(comparator com):定制排序
//自然排序 定制排序
@Test
public void test13(){
List<String> list = Arrays.asList("aaa", "ccc", "eee", "ddd", "bbb");
list.stream()
.sorted()
.forEach(System.out::println);
peopleList.stream()
.sorted((a,b)->{
if (a.getAge()==b.getAge()){
return a.getName().compareTo(b.getName());
}else {
return Integer.compare(a.getAge(),b.getAge());
}
})
.forEach(System.out::println);
}
三、终止操作
查找和匹配
allmatch:查找是否匹配所有元素
anymatch:检查是否至少匹配一个元素
nonematch:是否全部都不匹配
findfirst:返回第一个元素
findany:返回当前流中的任意元素
count:返回当前流中元素的总数
max:返回流中的最大值 min:返回流中的最小值
就懒了,这里就没敲代码了,直接就能点出来,会有提示。☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺
归约 :reduce 可以将流中的元素反复结合起来得到一个值
@Test
public void test14(){
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
Integer sum = list.stream()
.reduce(0, (a, b) -> a + b);
//这里的意思是先把0赋值给a 1赋值给b 加的结果再赋值给a,2赋值给b 以此类推
System.out.println(sum);
}
收集:collect 将流转换成其他形式。接收一个collector接口的实现,用于给stream中元素做汇总的方法
@Test
public void test15(){
List<String> list = peopleList.stream()
.map(People::getName)
.collect(Collectors.toList());
ArrayList<String> arrayList = peopleList.stream()
.map(People::getName)
.collect(Collectors.toCollection(ArrayList::new));
Set<String> set = peopleList.stream()
.map(People::getName)
.collect(Collectors.toSet());
HashSet<String> hashSet = peopleList.stream()
.map(People::getName)
.collect(Collectors.toCollection(HashSet::new));
//总数
peopleList.stream()
.collect(Collectors.counting());
//平均值
peopleList.stream()
.collect(Collectors.averagingDouble(People::getAge));
//总和
peopleList.stream()
.collect(Collectors.summarizingDouble(People::getAge));
//最大值
Optional<People> maxAgePeople = peopleList.stream()
.collect(Collectors.maxBy((a, b) -> Double.compare(a.getAge(), b.getAge())));
//最小值
Optional<Integer> minAge = peopleList.stream()
.map(People::getAge)
.collect(Collectors.minBy(Integer::compare));
//多级分组---应该可以返回树图,就是不知道具体怎么写
Map<Character, Map<String, List<People>>> collect = peopleList.stream()
.collect(Collectors.groupingBy(People::getSex, Collectors.groupingBy(a -> {
if (a.getAge() > 15) {
return "测试";
} else {
return "测试1";
}
})));
System.out.println(collect);
}
并行流(parallelStream)和顺序流:
并行流就是把一个内容分成多个数据块,并用不同的线程处理每个数据块的流。
顺序流的话感觉就是单线程操作的,并行流的话感觉就像是多线程操作。想清楚了解的话可以看一下fork/join框架。
@Test
public void test16(){
Instant start=Instant.now();
long sum = 0L;
for (long i=0;i<=100000000000L;i++){
sum+=i;
}
Instant end=Instant.now();
System.out.println("消耗的时间为:"+ Duration.between(start,end).toMillis());//消耗的时间为:44917
System.out.println("==========================");
Instant start1=Instant.now();
LongStream.rangeClosed(0,100000000000L)
.parallel()
.reduce(0,Long::sum);
Instant end1=Instant.now();
System.out.println("消耗的时间为:"+ Duration.between(start1,end1).toMillis());//消耗的时间为:38589
}
总结
这个写起来特别简单,代码量会少很多,毕竟是大佬封装好的,拿来直接用就可以了。
**注意:**项目中给不给使用还是问清楚比较好,毕竟不懂lambda的是看不懂你写的啥。维护起来可能会比较吃力。会被骂的。。。