六、JDK1.8—Stream API

Stream

Stream 是 Java8 中處理集合的關鍵抽象概念,它可以指定你希望對集合進行的操作,可以執行非常複雜的查找、過濾和映射數據等操作。使用Stream API 對集合數據進行操作,就類似於使用 SQL 執行的數據庫查詢。也可以使用 Stream API 來並行執行操作。簡而言之,Stream API 提供了一種高效且易於使用的處理數據的方式。

注意:
      ①Stream 自己不會存儲元素。
      ②Stream 不會改變源對象。相反,他們會返回一個持有結果的新Stream。
      ③Stream 操作是延遲執行的。這意味着他們會等到需要結果的時候才執行

 Stream 的操作三個步

創建 Stream
     一個數據源(如:集合、數組),獲取一個流 

中間操作
     一箇中間操作鏈,對數據源的數據進行處理 

終止操作(終端操作)
      一個終止操作,執行中間操作鏈,併產生結

 

創建 Stream

@Test//創建Stream
public void test() {
	//1. Collection 提供了兩個方法  stream() 與 parallelStream()
	List<String> list = new ArrayList<>();
	Stream<String> stream = list.stream(); //獲取一個順序流
	Stream<String> parallelStream = list.parallelStream(); //獲取一個並行流

	//2. 通過 Arrays 中的 stream() 獲取一個數組流
	Integer[] numArr = new Integer[10];
	Stream<Integer> stream1 = Arrays.stream(numArr);

	//3. 通過 Stream 類中靜態方法 of()
	Stream<Integer> stream2 = Stream.of(1, 2, 3, 4, 5, 6);
	Stream<Integer> stream25 = Stream.of(numArr);//數組

	//4. 創建無限流
	//4.1迭代
	Stream<Integer> stream3 = Stream.iterate(0, (x) -> x + 2);//創建 Stream
	stream3.limit(10) //中間操作
			.forEach(System.out::println);//終止操作(終端操作)

	//4.2生成
	Stream<Double> stream4 = Stream.generate(Math::random);//創建 Stream
	stream4.limit(2)//中間操作
			.forEach(System.out::println);//終止操作(終端操作)
}

中間操作 

public class TestLDemo {

	List<Employee> emps = Arrays.asList(
			new Employee(102, "李四", 59, 6666.66),
			new Employee(101, "張三", 18, 9999.99),
			new Employee(103, "王五", 28, 3333.33),
			new Employee(104, "趙六", 8, 7777.77),
			new Employee(104, "趙六", 8, 7777.77),
			new Employee(104, "趙六", 8, 7777.77),
			new Employee(105, "田七", 38, 5555.55)
	);

	/*
	Stream 的中間操作
	篩選與切片
		filter--接收 Lambda , 從流中排除某些元素。
		limit--截斷流,使其元素不超過給定數量。
		skip(n) -- 跳過元素,返回一個扔掉了前 n 個元素的流。若流中元素不足 n 個,則返回一個空流。與 limit(n) 互補
		distinct--篩選,通過流所生成元素的 hashCode() 和 equals() 去除重複元素
	 */
	@Test
	public void test1() {

		//所有的中間操作不會做任何的處理 正中間操作後產生一個新的Stream
		Stream<Employee> stream = emps.stream()
									   .distinct()
				                       .filter((employee) -> {
											System.out.println("測試中間操作");
										    return employee.getAge() <= 35;
										})
										.limit(3)
										.skip(2);


		//只有當做終止操作時,所有的中間操作會一次性的全部執行,稱爲“惰性求值”
		stream.forEach(System.out::println);

	}

	/*
	Stream 的中間操作
	映射
		map(Function f)--接收一個函數作爲參數,該函數會被應用到每個元 素上,並將其映射成一個新的元素。
	        flatMap(Function f)--接收一個函數作爲參數,將流中的每個值都換成另 一個流,然後把所有流連接成一個流
                mapToDouble(ToDoubleFunction f)--接收一個函數作爲參數,該函數會被應用到每個元 素上,產生一個新的 DoubleStream。 
	        mapToInt(ToIntFunction f)--接收一個函數作爲參數,該函數會被應用到每個元 素上,產生一個新的 IntStream。 
	        mapToLong(ToLongFunction f)--接收一個函數作爲參數,該函數會被應用到每個元 素上,產生一個新的 LongStream。
	 */
	@Test
	public void test2() {
		List<String> list = Arrays.asList("aaa","bbb","ccc");
		list.stream()
				.map((str)-> str.toUpperCase())
				.forEach(System.out::println);
		//AAA BBB CCC

		emps.stream().map(Employee::getName)
				.forEach(System.out::println);
		//提取所有員工的名字
	}

	/*
	Stream 的中間操作
	排序
		sorted()--產生一個新流,其中按自然順序排序(按照對象的Comparable)
                sorted(Comparator comp)--產生一個新流,其中按比較器順序排序
	 */
	@Test
	public void test3() {
		emps.stream()
				.sorted((emp1,emp2)->{
					if(emp1.getAge()== emp2.getAge()){
						return emp1.getName().compareTo(emp2.getName());
					}else{
						return Integer.valueOf(emp1.getAge()).compareTo(emp2.getAge());
					}
				})
		.forEach(System.out::println);
	}

}

終止操作(終端操作)

public class TestLDemo {

	List<Employee> emps = Arrays.asList(
			new Employee(102, "李四", 59, 6666.66),
			new Employee(101, "張三", 18, 9999.99),
			new Employee(103, "王五", 28, 3333.33),
			new Employee(104, "趙六", 8, 7777.77),
			new Employee(104, "趙六", 3, 7777.77),
			new Employee(104, "趙六", 8, 7777.77),
			new Employee(105, "田七", 38, 5555.55)
	);

	/*
	Stream 終止操作
	查找與匹配
		allMatch(Predicate p)--檢查是否匹配所有元素
		anyMatch(Predicate p)--檢查是否至少匹配一個元素
		noneMatch(Predicate p)--檢查是否沒有匹配所有元素
		findFirst()--返回第一個元素
		findAny()--返回當前流中的任意元素
		count()--返回流中元素總數
		max(Comparator c)--返回流中最大值
		min(Comparator c)--返回流中最小值
		reduce(T iden, BinaryOperator b)--可以將流中元素反覆結合起來,得到一個值。 返回 T 歸約 reduce(BinaryOperator b) 可以將流中元素反覆結合起來,得到一個值。 返回 Optional<T> 備註:map 和 reduce 的連接通常稱爲 map-reduce 模式,因 Google 用它 來進行網絡搜索而出名。
		forEach(Consumer c)--內部迭代(使用 Collection 接口需要用戶去做迭 代,稱爲外部迭代。相反,Stream API 使用內部 迭代——它幫你把迭代做了)
	 */
	@Test
	public void test1() {

		//所有的員工是否都叫張三
		boolean b1 = emps.stream()
				.allMatch((emp)-> "張三".equals(emp.getName()));
		System.out.println(b1);//false

		//是否有員工叫張三
		boolean b2 = emps.stream()
				.anyMatch((emp) -> "張三".equals(emp.getName()));
		System.out.println(b2);//true

		//所有的員工是否都不叫張三
		boolean b3 = emps.stream()
				.noneMatch((emp) -> "張三".equals(emp.getName()));
		System.out.println(b3);//false

		//獲取到員工工資最低的員工信息
		Optional<Employee> optional = emps.stream()
				.sorted((emp1,emp2)->Double.compare(emp1.getSalary(),emp2.getSalary()))
				.findFirst();//Optional  防止空指針異常   將對象封裝在Optional 中
		System.out.println(optional.get());

		//員工中工資最高(最低)的是多少
		Optional<Double> max = emps.stream()
				.map(Employee::getSalary)//先獲取所有的工資數
				.max(Double::compareTo);
		System.out.println(max.get());

	}

	/*
	Stream 終止操作
	歸約
		reduce(T iden, BinaryOperator b)--可以將流中元素反覆結合起來,得到一個值。 返回 T 歸約
		reduce(BinaryOperator b)--可以將流中元素反覆結合起來,得到一個值。 返回 Optional<T>
	收集
		collect(Collector c)--將流轉換爲其他形式。接收一個 Collector接口的 實現,用於給Stream中元素做彙總的方法
	 */
	@Test
	public void test2() {
		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);//55

		Integer reduce1 = list.stream()
				.reduce(100, (x, y) -> x + y);
		System.out.println(reduce1);//155  //此處的reduce返回不是Optional  因爲他有其起始值不可能爲空

		//求所有員工工資的總和
		Optional<Double> reduce2 = emps.stream()
				.map(Employee::getSalary)
				.reduce(Double::sum);  //此處的reduce返回Optional  因爲此結果有可能爲空   Double.sum(double a, double b)爲jdk1.8的新方法
		System.out.println(reduce2.get());

		//備註:map 和 reduce 的連接通常稱爲 map-reduce 模式,因 Google 用它 來進行網絡搜索而出名。


		//將emps的名字收集到List中
		List<String> collect1 = emps.stream()
				.map(Employee::getName)
				.collect(Collectors.toList());
		System.out.println(collect1);

		String collect12 = emps.stream()
				.map(Employee::getName)
				.collect(Collectors.joining(",","【","}"));
		System.out.println(collect12);//【李四,張三,王五,趙六,趙六,趙六,田七}

		//將emps的名字收集到Set中
		Set<String> collect2 = emps.stream()
				.map(Employee::getName)
				.collect(Collectors.toSet());
		System.out.println(collect2);

		//將emps的名字收集到Set中
		Set<String> collect3 = emps.stream()
				.map(Employee::getName)
				.collect(Collectors.toCollection(HashSet::new));
		System.out.println(collect3);

		//計算總數
		Long collect4 = emps.stream()
				.collect(Collectors.counting());
		System.out.println(collect4);

		//計算所有工資平均值
		Double collect5 = emps.stream()
				.collect(Collectors.averagingDouble(Employee::getSalary));
		System.out.println(collect5);

		//所有員工總和
		Double collect6 = emps.stream()
				.collect(Collectors.summingDouble(Employee::getSalary));
		System.out.println(collect6);

		//員工工資最大值的員工信息
		Optional<Employee> collect7 = emps.stream()
				.collect(Collectors.maxBy((emp1, emp2) -> Double.compare(emp1.getSalary(), emp2.getSalary())));
		System.out.println(collect7);

		//員工工資最小值
		Optional<Double> max = emps.stream()
				.map(Employee::getSalary)//先獲取所有的工資數
				.max(Double::compareTo);
		System.out.println(max.get());

		//獲得所有員工信息中 工資 對應的組函數信息
		DoubleSummaryStatistics collect = emps.stream()
				.collect(Collectors.summarizingDouble(Employee::getSalary));
		System.out.println(collect);//DoubleSummaryStatistics{count=7, sum=48888.840000, min=3333.330000, average=6984.120000, max=9999.990000}
		System.out.println(collect.getSum());
		System.out.println(collect.getCount());
		System.out.println(collect.getAverage());
		System.out.println(collect.getMax());
		System.out.println(collect.getMin());

		//按照姓名分組
		Map<String, List<Employee>> collect8 = emps.stream()
				.collect(Collectors.groupingBy(Employee::getName));
		System.out.println(collect8);
		/*{
			李四 = [Employee[id = 102, name = 李四, age = 59, salary = 6666.66]],
			張三 = [Employee[id = 101, name = 張三, age = 18, salary = 9999.99]],
			王五 = [Employee[id = 103, name = 王五, age = 28, salary = 3333.33]],
			趙六 = [Employee[id = 104, name = 趙六, age = 8, salary = 7777.77],Employee[id = 104, name = 趙六, age = 8, salary = 7777.77],Employee[id = 104, name = 趙六, age = 8, salary = 7777.77]],
			田七 = [Employee[id = 105, name = 田七, age = 38, salary = 5555.55]]
		}*/


		//多級分組 先按照姓名分組,再按照年齡分組
		Map<String, Map<Integer, List<Employee>>> collect9 = emps.stream()
				.collect(Collectors.groupingBy(Employee::getName, Collectors.groupingBy(Employee::getAge)));
		System.out.println(collect9);
		/*{
			李四 = {
				59 = [Employee[id = 102, name = 李四, age = 59, salary = 6666.66]]
			}, 張三 = {
				18 = [Employee[id = 101, name = 張三, age = 18, salary = 9999.99]]
			}, 王五 = {
				28 = [Employee[id = 103, name = 王五, age = 28, salary = 3333.33]]
			}, 趙六 = {
				3 = [Employee[id = 104, name = 趙六, age = 3, salary = 7777.77]],
				8 = [Employee[id = 104, name = 趙六, age = 8, salary = 7777.77], Employee[id = 104, name = 趙六, age = 8, salary = 7777.77]]
			}, 田七 = {
				38 = [Employee[id = 105, name = 田七, age = 38, salary = 5555.55]]
			}
		  }
		*/

		//自定義分組
		Map<String, Map<String, List<Employee>>> collect11 = emps.stream()
				.collect(Collectors.groupingBy(Employee::getName, Collectors.groupingBy((emp) -> {
					if (((Employee) emp).getAge() <= 3) {
						return "嬰兒";
					} else {
						return "少年";
					}
				})));
		System.out.println(collect11);
		/*{
			李四 = {
				少年 = [Employee[id = 102, name = 李四, age = 59, salary = 6666.66]]
			}, 張三 = {
				少年 = [Employee[id = 101, name = 張三, age = 18, salary = 9999.99]]
			}, 王五 = {
				少年 = [Employee[id = 103, name = 王五, age = 28, salary = 3333.33]]
			}, 趙六 = {
				嬰兒 = [Employee[id = 104, name = 趙六, age = 3, salary = 7777.77]],
				少年 = [Employee[id = 104, name = 趙六, age = 8, salary = 7777.77], Employee[id = 104, name = 趙六, age = 8, salary = 7777.77]]
			}, 田七 = {
				少年 = [Employee[id = 105, name = 田七, age = 38, salary = 5555.55]]
			}
		  }
	    */



		//分區:滿足條件的一個區  不滿足條件的一個區
		Map<Boolean, List<Employee>> collect10 = emps.stream()
				.collect(Collectors.partitioningBy((e) -> e.getSalary() > 8000));
		System.out.println(collect10);
		/*
			false = [Employee[id = 102, name = 李四, age = 59, salary = 6666.66],
			         Employee[id = 103, name = 王五, age = 28, salary = 3333.33],
			         Employee[id = 104, name = 趙六, age = 8, salary = 7777.77],
			         Employee[id = 104, name = 趙六, age = 3, salary = 7777.77],
			         Employee[id = 104, name = 趙六, age = 8, salary = 7777.77],
			         Employee[id = 105, name = 田七, age = 38, salary = 5555.55]],
			true = [Employee[id = 101, name = 張三, age = 18, salary = 9999.99]]
		}*/
	}

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章