由於最近換了工作,項目中是使用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);//順序執行
}
}