天天看點

Java8 Stream API學習Stream是什麼?

Java8 Stream API使用示例

Stream是什麼?

Java8中的Stream,也叫流,不過不同于IO流,它是對集合操作的一個增強API,個人了解,1、它使用内部疊代操作集合;2、它提供了類似資料庫中count、avg等聚合操作,學習過程中留個記錄,話不多說,上代碼。

import java.util.ArrayList;
import java.util.Comparator;
import java.util.DoubleSummaryStatistics;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalDouble;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamDemo {
	public static void main(String[] args) {
		/**
		 * 建立流
		 * 1、Collection等通過stream()方法、Arrays中得靜态方法stream()擷取數組流
		 * 2、Stream.of(),Stream.iterate()、Stream.generate()無限流
		 */
		//初始化資料
		List<Student> list = new ArrayList<>();
		list.add(new Student(5, "張三", 22,"國文", 85));
		list.add(new Student(1, "李四", 23,"數學", 86));
		list.add(new Student(4, "麻子", 21,"國文", 82));
		list.add(new Student(6, "麻子", 21,"英語", 98));
		list.add(new Student(2, "張三", 22,"數學", 99));
		list.add(new Student(7, "李四", 23,"國文", 90));
		//list.add(new Student(8, "李四", 23,"國文", 90)); //測試去重的時候可以加上這條記錄
		
		/*
		 * 1.1、filter 過濾資料,留下入參傳回true的資料
		 * 需求:查詢分數大于90的人
		 */
		List<Student> collect = list.stream().filter(s -> s.getScore()>90).collect(Collectors.toList());
		System.out.println("1.1、filter 查詢分數大于90的人:"+collect);
		
		/*
		 * 1.2、filter 過濾資料,留下入參傳回true的資料
		 * 需求:查詢國文分數大于等于90的人
		 */
		List<Student> c2 = list.stream()
				.filter(s -> {
			       if(s.getSubject().equals("國文") && s.getScore()>=90){
			    	   return true;
			       }else{
			    	   return false;
			       }
			    }).collect(Collectors.toList());
		System.out.println("1.2、filter 查詢國文分數大于等于90的人:"+c2);
		
		/*
		 *這裡輸出用了lambda的方法引用 
		 *概念:對于一個lambda表達式隻是調用了一個方法時,可以用方法引用的方式簡化lambda表達式
		 *方法引用的标準形式是:類名::方法名。(注意:隻需要寫方法名,不需要寫括号)
			有以下四種形式的方法引用:
			類型	示例
			引用靜态方法	ContainingClass::staticMethodName
			引用某個對象的執行個體方法	containingObject::instanceMethodName
			引用某個類型的任意對象的執行個體方法	ContainingType::methodName
			引用構造方法	ClassName::new
		 *
		 */
		list.stream()
				.filter(s -> {
			       if(s.getSubject().equals("國文") && s.getScore()>=90){
			    	   return true;
			       }else{
			    	   return false;
			       }
			    }).forEach(System.out::println); //方法引用
		
		/*
		 * 2.1、map 轉換,可以将原對象轉換成另一個對象流
		 * 典型需求:得到id清單
		 */
		List<Integer> idList = list.stream().map(Student::getId).collect(Collectors.toList());
		System.out.println("2.1、map 由List<Student>轉換後得到List<Integer>id清單:"+idList);
		
		/*
		 * 2.2、mapToDouble 轉換,可以将原對象流轉換成Double流
		 * 典型需求:求張三的平均分
		 */
		OptionalDouble average = list.stream()
				.filter(s -> s.getName().equals("張三")) //保留張三的記錄
				.mapToDouble(Student::getScore) //将分數轉成一個mapToDouble流
				.average(); //求平均分
		DoubleSummaryStatistics summary = list.stream()
				.filter(s -> s.getName().equals("張三")) //保留張三的記錄
				.mapToDouble(Student::getScore) //将分數轉成一個mapToDouble流
				.summaryStatistics();
		System.out.println("2、mapToDouble 求張三的平均分:" + (average.isPresent()?average.getAsDouble():average.orElse(0)));
		System.out.println("2、summaryStatistics 張三分數統計:" + "總分:"+summary.getSum()+",最高分:"+summary.getMax()+",最低分:"+summary.getMin()+",共幾科:"+summary.getCount()+",平均分:"+summary.getAverage());
		
		/*
		 * 3、distinct 去重,根據對象的hashCode和equals方法去重
		 * 典型需求:清單去重
		 */
		List<Student> distinctList = list.stream().distinct().collect(Collectors.toList());
		System.out.println("3、distinct 去重後清單:"+distinctList);
		
		/*
		 * 4、sort 排序,可以自定義排序規則
		 * 需求:先根據姓名升序,再根據科目升序,在再根據分數降序
		 */
		List<Student> sortedList = list.stream().sorted(Comparator.comparing(Student::getName) //姓名升序
				//.thenComparing(Student::getSubject) //科目升序
				.thenComparing(Student::getScore).reversed()) //分數降序
		.collect(Collectors.toList());
		System.out.println("4、sort 先根據姓名升序,再根據科目升序,在再根據分數降序:"+sortedList);
		
		/*
		 * 5、peek 什麼都不幹,一般用于調試,輸出元素啥的
		 * 按照Java團隊的說法,peek()方法存在的主要目的是用調試,通過peek()方法可以看到流中的資料經過每個處理點時的狀态
		 * 需求:過濾長度大于3的字元串,轉成大寫
		 */
		Stream.of("one", "two", "three", "four")
        .filter(e -> e.length() > 3) //長度大于3的,得到 "three", "four"
        .peek(e -> System.out.println("Filtered value: " + e))
        .map(String::toUpperCase) // 轉成大寫
        .peek(e -> System.out.println("Mapped value: " + e))
        .collect(Collectors.toList());
		
		/*
		 * 6、limit 截取前N條資料
		 * 需求:截取前3條資料
		 */
		List<Student> limitList = list.stream().limit(3)
		.collect(Collectors.toList());
		System.out.println("6、limit 截取前3條資料:"+limitList);
		
		/*
		 * 6、skip 跳過N條資料
		 * 需求:跳過1條資料
		 */
		List<Student> skipList = list.stream().skip(1)
				.collect(Collectors.toList());
		System.out.println("7、skip 跳過1條資料:"+skipList);
		
		/*
		 * 7.1、reduce 歸約(把值合成一個)  使用隻有一個入參的情況
		 * Optional<T> reduce(BinaryOperator<T> accumulator); 
		 * 需求:求和
		 */
		Optional<Integer> accResult = Stream.of(1, 2, 3, 4)
				.reduce((acc, item) -> { //第一個參數是統計值,第一次執行是第一個元素;第二個參數是流元素,第一次是第二個元素
					System.out.println("acc : "  + acc); //統計結果,第一次執行是第一個元素
					acc += item;
					System.out.println("item: " + item); //流裡面的元素,第一次是第二個元素
					System.out.println("acc+ : "  + acc); //統計結果
					System.out.println("--------");
					return acc;
				});
		System.out.println("7.1、reduce 歸約  使用隻有一個入參的情況   統計結果: " + accResult.get());
		System.out.println("--------");
		
		/*
		 * 7.2、reduce 歸約(把值合成一個)  使用有兩個入參的情況,第一個入參是統計初始值,第二個是累加器
		 * T reduce(T identity, BinaryOperator<T> accumulator); 
		 * param :identity 是傳回結果
		 * param:accumulator 累加器
		 * 需求:求和
		 */
		Integer accResult2 = Stream.of(1, 2, 3, 4)
				.reduce(0,(acc, item) -> { //第一個參數0是統計結果初始值;第二個參數是累加器,跟上面一樣
					System.out.println("acc2 : "  + acc); //統計結果,第一次執行是初始值0
					acc += item;
					System.out.println("item2: " + item); //流裡面的元素,第一次是第1個元素
					System.out.println("acc2+ : "  + acc); //統計結果
					System.out.println("--------");
					return acc;
				});
		System.out.println("7.2、reduce 歸約  使用有兩個入參的情況  統計結果2: " + accResult2);
		System.out.println("--------");
		
		/*
		 * 8.1、Collectors.groupingBy
		 * 需求:根據姓名分組
		 * return Map<String, List<Student>>, key姓名,value:該姓名對應的對象清單
		 */
		Map<String, List<Student>> groupList = list.stream()
				.collect(Collectors.groupingBy(Student::getName));
		System.out.println("8.1、Collectors.groupingBy 根據姓名分組:"+groupList);
		
		/*
		 * 8.2、Collectors.groupingBy
		 * 需求:根據姓名分組,并統計每個分組有多少個元素(count)
		 * return Map<String, Long>, key:姓名,value:該組有多少個元素
		 * 例:{李四=2, 張三=2, 麻子=2}
		 */
		Map<String, Long> groupCount = list.stream()
				.collect(Collectors.groupingBy(Student::getName,Collectors.counting()));
		System.out.println("8.2、Collectors.groupingBy 根據姓名分組,并統計每個分組有多少個(count):"+groupCount);
		
		/*
		 * 8.3、Collectors.groupingBy
		 * 需求:根據姓名分組,并統計每個分組各科平均分
		 * return Map<String, Double>, key:姓名,value:平均分
		 * 例:{李四=88.0, 張三=92.0, 麻子=90.0}
		 */
		Map<String, Double> groupAvg = list.stream()
				.collect(Collectors.groupingBy(Student::getName,Collectors.averagingDouble(Student::getScore)));
		System.out.println("8.3、Collectors.groupingBy 根據姓名分組,并統計每個分組各科平均分:"+groupAvg);
		
		/*
		 * 8.4、Collectors.groupingBy
		 * 需求:根據姓名分組,并統計每個分組總分
		 * return Map<String, Double>, key:姓名,value:總分
		 * 例:{李四=176.0, 張三=184.0, 麻子=180.0}
		 */
		Map<String, Double> groupSum = list.stream()
				.collect(Collectors.groupingBy(Student::getName,Collectors.summingDouble(Student::getScore)));
		System.out.println("8.4、Collectors.groupingBy 根據姓名分組,并統計每個分組總分:"+groupSum);
		
		/*
		 * 8.5、Collectors.groupingBy 多字段分組
		 * 需求:根據姓名,學科分組
		 * return Map<String, Map<String, List<Student>>>, key:姓名,value:map(key:學科,value:清單)
		 * 例:{李四={數學=[Student [name=李四, subject=數學, score=86.0]], 國文=[Student [name=李四, subject=國文, score=90.0]]}, 張三={數學=[Student [name=張三, subject=數學, score=99.0]], 國文=[Student [name=張三, subject=國文, score=85.0]]}, 麻子={國文=[Student [name=麻子, subject=國文, score=82.0]], 英語=[Student [name=麻子, subject=英語, score=98.0]]}}
		 */
		Map<String, Map<String, List<Student>>> groups = list.stream()
				.collect(Collectors.groupingBy(Student::getName,Collectors.groupingBy(Student::getSubject)));
		System.out.println("8.5、Collectors.groupingBy 多字段分組-根據姓名,學科分組:"+groups);
	}
	
	private static class Student{
		private int id; //id
		private String name; //姓名
		private int age; //年齡
		private String subject; //學科
		private float score; //分數
		public Student(int id,String name,int age,String subject,float score){
			this.id=id;
			this.name=name;
			this.age=age;
			this.subject=subject;
			this.score=score;
		}
		public int getId() {
			return id;
		}
		@SuppressWarnings("unused")
		public void setId(int id) {
			this.id = id;
		}
		public String getName() {
			return name;
		}
		@SuppressWarnings("unused")
		public void setName(String name) {
			this.name = name;
		}
		@SuppressWarnings("unused")
		public int getAge() {
			return age;
		}
		@SuppressWarnings("unused")
		public void setAge(int age) {
			this.age = age;
		}
		public float getScore() {
			return score;
		}
		@SuppressWarnings("unused")
		public void setScore(float score) {
			this.score = score;
		}
		@Override
		public String toString() {
			return "Student [name=" + name + ", subject=" + subject + ", score=" + score + "]";
		}
		public String getSubject() {
			return subject;
		}
		@SuppressWarnings("unused")
		public void setSubject(String subject) {
			this.subject = subject;
		}
		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + ((name == null) ? 0 : name.hashCode());
			result = prime * result + ((subject == null) ? 0 : subject.hashCode());
			return result;
		}
		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			Student other = (Student) obj;
			if (name == null) {
				if (other.name != null)
					return false;
			} else if (!name.equals(other.name))
				return false;
			if (subject == null) {
				if (other.subject != null)
					return false;
			} else if (!subject.equals(other.subject))
				return false;
			return true;
		}
	}
}