由于最近换了工作,项目中是使用jdk1.8,所以有必要学习一些jdk1.8骚操作,此文章不断更新。
如何理解Stream?在我看来,Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。简单来说,它的作用就是通过一系列操作将数据源(集合、数组)转化为想要的结果。
Stream有三点非常重要的特性:
- Stream 是不会存储元素的。
- Stream 不会改变原对象,相反,他们会返回一个持有结果的新Stream。
- Stream 操作是延迟执行的。意味着它们会等到需要结果的时候才执行。
Stream生成
//Collection系的 stream() 和 parallelStream()
List<String> list = new ArrayList<> ();
Stream<String> stream = list.stream();
Stream<String> stringStream = list.parallelStream();
//通过Arrays.stram()
Stream<String> stream1 = Arrays.stream(new String[10]);
//通过Stream.of()
Stream<Integer> stream2 = Stream.of(1, 2, 3,4,5,6,7,8,9,10);
//通过Stream.iterate()生成无限流
Stream<Integer> iterate = Stream.iterate(0, (x) -> x + 2);
iterate.limit(10).forEach(System.out::println);
//通过Stream.generate()
Stream<Double> generate = Stream.generate(() -> Math.random());
Stream中间操作
stream2.map(s -> s + 1) //映射
.flatMap(s -> Stream.of(s)) //和map差不多,但返回类型为Stream,类似list.add()和list.addAll()的区别
.filter(s -> s <=5 ) //过滤
.limit(5) //限制
.skip(1) //跳过
.distinct() //去重
.sorted() //自然排序
.sorted(Integer::compareTo).forEach (System.out::println); //自定义排序*/
Stream的终止操作 (不能对同一个流一遍进行运行操作,一遍终止操作)
常用的终止API如下:
System.out.println (stream2.allMatch((x) -> x == 10)); // 检查是否匹配所有元素 boolean
System.out.println(stream2.anyMatch(((x) -> x>5))); // 检查是否至少匹配一个元素
System.out.println(stream2.noneMatch((x) -> x>500)); //检查是否没有匹配所有元素
System.out.println (stream2.findFirst()); // 返回第一个元素Optional[1]
System.out.println (stream2.findAny()); // 返回当前流中的任意一个元素;
System.out.println (stream2.count()); // 返回流中元素的总个数);
Optional<Integer> max = stream2.max(Integer::compareTo); // 返回流中最大值
System.out.println("max "+max.get());
Optional<Integer> min = stream2.min(Integer::compareTo);//返回流中最小值
System.out.println("min "+min.get());
reduce (归约):将流中元素反复结合起来得到一个值
Integer reduce = stream2.map(s -> (s + 1)).reduce(0, (integer1, integer2) -> integer1+integer2);
//归约:0为第一个参数x的默认值,x是计算后的返回值,y为每一项的值。
System.out.println(reduce);
Optional<Integer> reduce1 = stream2.map(s -> (s + 1)).reduce((x, y) -> x + y);
// x是计算后的返回值,默认为第一项的值,y为其后每一项的值。
System.out.println(reduce1.get ());
collect(收集):将流转换为其他形式。需要Collectors类的一些方法
//collect(收集):将流转换为其他形式。需要Collectors类的一些方法。
Set<Integer> collect = stream2.collect(Collectors.toSet());
List<Integer> collect2 = stream2.collect(Collectors.toList());
HashSet<Integer> collect1 = stream2.collect(Collectors.toCollection(HashSet::new));
//分组 {group=[1, 2, 3, 4...]}
Map<String, List<Integer>> collect3 = stream2.collect(Collectors.groupingBy((x) -> "group"));//将返回值相同的进行分组
//分区 {false=[1, 2, 3, 4], true=[5, 6, 7, 8, 9, 10, 10]}
Map<Boolean, List<Integer>> collect5 = stream2.collect(Collectors.partitioningBy((x) -> x >= 5));
//汇总 最大值、最小值、平均值、个数
DoubleSummaryStatistics collect6 = stream2.collect(Collectors.summarizingDouble((x) -> x));
System.out.println(collect6.getMax());
System.out.println(collect6.getCount());
摘自: https://mp.weixin.qq.com/s/5UUD7N4Uxspnzcine_2AnA
工作常用示例
package JDK8常用特性;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author Heian
* @time 19/04/01 14:15
* 用途:
*/
public class Demo1 {
class Student{
private int id;
private String name;
private int age;
public Student(int id,String name,int age){
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
public static void main(String[] args) {
Demo1 demo1 = new Demo1 ();
List<Student> list = new ArrayList<> ();
list.add (demo1.new Student (1,"张三",18));
list.add (demo1.new Student (2,"李四",20));
list.add (demo1.new Student (3,"王二",22));
list.add (demo1.new Student (4,"小明",19));
list.add (demo1.new Student (5,"小红",17));
list.add (null);
//常用操作一:防空处理
//Optional.ofNullable (list).orElse (Collections.emptyList ()).forEach (System.out::println); 会存在null
list.stream ().filter (Objects::nonNull).forEach (student -> System.out.println (student));
//常用操作二:集合变形 业务代码最为常见(假设我要取得某个集合中某个属性作为单独的一个集合)
System.out.println ("=======================集合变形分割线===================");
List<String> nameList = list.stream ().filter (Objects::nonNull).map (Student::getName).collect(Collectors.toList());
nameList.forEach (System.out::println);//集合转化流--->filter过滤--->map对集合做业务操作(返回的仍然是Stream<R>)--->流转化为集合
//limit 就像mysql的limit num 关键字 这里是查出前3条
List<String> nameList2 = list.stream ().filter (Objects::nonNull).map (Student::getName).limit (3).collect(Collectors.toList());
nameList2.forEach (s -> System.out.println ("limit" + s));
//加上skip 类似于mysql分页 比如查看第1 到 10 条记录 select * from emp limit 0,9 这里也类似:这就是第2到第4条 也可以用于分页
List<String> nameList3 = list.stream ().filter (Objects::nonNull).map (Student::getName).skip (1).limit (3).collect(Collectors.toList());
nameList3.forEach (s -> System.out.println ("skip limit" + s));
List<Integer> list2 = Arrays.asList(1,2,3);
//不改变原有元素
list2.forEach(i -> i = i*2);
list2.forEach(integer -> System.out.println ("不改变原有元素"+integer));
//改变对象
list2.stream().map(i -> i * 2).forEach(integer -> System.out.println ("改变原有元素"+integer));
//常用操作三:list转map
System.out.println ("=======================list转map分割线===================");
Map<Integer,Student> map = list.stream ().filter (Objects::nonNull).collect (Collectors.toMap (Student::getId,student -> student));
for (Map.Entry<Integer, Demo1.Student> entrySet: map.entrySet ()){
System.out.println (entrySet.getKey () +":"+ entrySet.getValue ());
}
System.out.println ("=======================排序后分割线===================");
//常用操作四:集合排序
//方法1:利用Comparable 接口实现排序 String和Integer都是实现了此接口,需要覆写其
List<Student> notNullList = list.stream ().filter (Objects::nonNull).collect (Collectors.toList ());
Collections.sort (notNullList,(o1, o2) -> {
return Integer.compare (o1.age,o2.age);
});
//利用Comparator 接口实现排序
Collections.sort (notNullList,Comparator.comparing (o -> o.age));
notNullList.forEach (student -> System.out.println (student));
//当然觉得性能差 可以用并行方式输出,但结果不一定是顺序执行 1234...9
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
numbers.parallelStream().forEach(System.out::println);
numbers.parallelStream ().forEachOrdered (System.out::println);//顺序执行
}
}