Java8新特性之Stream API

概述

       流(Stream):是數據渠道,用於操做數據源(集合、數組等)所生成的元素序列。java

      「集合講的是數據,流講的是計算」數組

StreamAPI特色

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

StreamAPI操做步驟

1. 建立Stream

//建立 Stream
	@Test
	public void test1(){
		//1.Collection 提供了兩個方法  stream() 與 parallelStream()
		List<String> list = new ArrayList<>();
		Stream<String> stream1 = list.stream();

		//2.經過 Arrays 中的 stream() 獲取一個數組流
		Employee[] employees = new Employee[10];
		Stream<Employee> stream2 = Arrays.stream(employees);

		//3. 經過 Stream 類中靜態方法 of()
		List<String> list1 = Arrays.asList("12", "as", "df");
		Stream stream3 = Stream.of(list1);

		//4. 建立無限流
		//迭代
		Stream stream4 = Stream.iterate(1, x -> x + 2);
		stream4.limit(10).forEach(System.out::println);
		//生成
		Stream stream5 = Stream.generate(Math::random);
		stream5.limit(5).forEach(System.out::println);
	}

 

2. 一系列流水史的中間操做

多箇中間操做能夠鏈接起來造成一個流水線,除非流水線上觸發終止操做,不然中間操做不會執行任何的處理!而在終止操做時一次性所有處理,稱爲「惰性求值」ide


① 篩選與切片

方法 描述
filter(Predicate p) 接收Lambda ,從流中排除某些元素
distinct() 篩選,經過流所生成元素的hashCode() 和equals() 去除重複元素
limit(long maxSize) 截斷流,使其元素不超過給定數量
skip(long n) 跳過元素,返回一個扔掉了前n 個元素的流。若流中元素不足n 個,則返回一個空流。與limit(n) 互補
//2. 中間操做
	List<Employee> employees = Arrays.asList(
			new Employee("張三", 20),
			new Employee("李四", 50),
			new Employee("王五", 40),
			new Employee("王五", 40),
			new Employee("王五", 40),
			new Employee("趙六", 10),
			new Employee("王琦", 8),
			new Employee("李逵", 4)
	);

	/**
	 * 篩選與切片
	 * filter(Predicate p) :接收Lambda ,從流中排除某些元素。
	 * distinct() :篩選,經過流所生成元素的hashCode() 和equals() 去除重複元素
	 * limit(long maxSize):截斷流,使其元素不超過給定數量。
	 * skip(long n):跳過元素,返回一個扔掉了前n 個元素的流。若流中元素不足n 個,則返回一個空流。與limit(n) 互補
	 */
	//內部迭代:由StreamAPI本身完成
	//filter(Predicate p) :接收Lambda ,從流中排除某些元素。
	@Test
	public void test2() {
		/*多箇中間操做能夠鏈接起來造成一個流水線,除非流水
		線上觸發終止操做,不然中間操做不會執行任何的處理!
		而在終止操做時一次性所有處理,稱爲「惰性求值」*/
		//中間操做:不會執行任何操做
		Stream<Employee> s = employees.stream().filter((e) -> {
			System.out.println("Stream API中間操做!");
			return e.getAge() > 25;
		});
		//終止操做:一次性操做所有操做
		s.forEach(System.out:: println);
	}

	//外部迭代
	@Test
	public void test3() {
		Iterator<Employee> it = employees.iterator();
		while (it.hasNext()) {
			Employee next = it.next();
			System.out.println(next);
		}
	}

	//limit(long maxSize):截斷流,使其元素不超過給定數量。
	@Test
	public void test4() {
		employees.stream()
				.filter(e -> e.getAge() > 30)
				.limit(3)
				.forEach(System.out:: println);
		//運行結果
		/*Employee{name='李四', age=50}
		Employee{name='王五', age=40}
		Employee{name='王五', age=40}*/
	}

	//skip(long n):跳過元素,返回一個扔掉了前n 個元素的流。若流中元素不足n 個,則返回一個空流。與limit(n) 互補
	@Test
	public void test5() {
		employees.stream()
				.filter(e -> e.getAge() > 30)
				.skip(1)
				.forEach(System.out:: println);
		//運行結果
		/*Employee{name='王五', age=40}
		Employee{name='王五', age=40}
		Employee{name='王五', age=40}*/
	}

	//distinct() :篩選,經過流所生成元素的hashCode() 和equals() 去除重複元素
	@Test
	public void test6() {
		employees.stream()
				.filter(e -> e.getAge() > 30)
				.distinct()
				.forEach(System.out:: println);
		//運行結果
		/*Employee{name='李四', age=50}
		  Employee{name='王五', age=40}*/
	}

②映射

方法    描述
map(Functionf) 接收一個函數做爲參數,該函數會被應用到每一個元素上,並將其映射成一個新的元素
mapToDouble(ToDoubleFunction f) 接收一個函數做爲參數,該函數會被應用到每一個元素上,產生一個新的DoubleStream
mapToInt(ToIntFunction f) 接收一個函數做爲參數,該函數會被應用到每一個元素上,產生一個新的IntStream
mapToLong(ToLongFunction f) 接收一個函數做爲參數,該函數會被應用到每一個元素上,產生一個新的LongStream
flatMap(Function f) 接收一個函數做爲參數,將流中的每一個值都換成另外一個流,而後把全部流鏈接成一個流
/**
	 * 映射
	 * map(Functionf) :接收一個函數做爲參數,該函數會被應用到每一個元素上,並將其映射成一個新的元素。
	 * mapToDouble(ToDoubleFunction f) :接收一個函數做爲參數,該函數會被應用到每一個元素上,產生一個新的DoubleStream。
	 * mapToInt(ToIntFunction f) :接收一個函數做爲參數,該函數會被應用到每一個元素上,產生一個新的IntStream。
	 * mapToLong(ToLongFunction f) :接收一個函數做爲參數,該函數會被應用到每一個元素上,產生一個新的LongStream。
	 * flatMap(Function f) :接收一個函數做爲參數,將流中的每一個值都換成另外一個流,而後把全部流鏈接成一個流
	 */
	@Test
	public void test7() {
		//map(Functionf) :接收一個函數做爲參數,該函數會被應用到每一個元素上,並將其映射成一個新的元素。
		List<String> list = Arrays.asList("aaa", "bbb", "ccc");
		list.stream()
				.map(str -> str.toUpperCase())
				.forEach(System.out:: print);//AAABBBCCC

		System.out.println("-------------------------");

		employees.stream()
				.map(Employee:: getName)
				.forEach(System.out:: print);//張三李四王五王五王五趙六王琦李逵

		System.out.println("-------------------------");
		//mapToInt(ToIntFunction f) :接收一個函數做爲參數,該函數會被應用到每一個元素上,產生一個新的IntStream。
		IntStream is = employees.stream()
								.mapToInt(Employee:: getAge);
		is.forEach(System.out::println);

		System.out.println("-------------------------");
		//flatMap(Function f) :接收一個函數做爲參數,將流中的每一個值都換成另外一個流,而後把全部流鏈接成一個流
		list.stream()
				.flatMap(TestStreamAPI1:: filterCharacter)
				.forEach(System.out:: println);

	}

	public static Stream<Character> filterCharacter(String str) {
		List<Character> list = new ArrayList<>();
		for (Character c : str.toCharArray()) {
			list.add(c);
		}
		return list.stream();
	}

③排序

方法 描述
sorted() 產生一個新流,其中按天然順序排序
sorted(Comparator comp) 產生一個新流,其中按比較器順序排序
/**
	 * 排序
	 * sorted() 產生一個新流,其中按天然順序排序(Comparable)
	   sorted(Comparator comp) 產生一個新流,其中按比較器順序排序(	Comparator)
	 */
	@Test
	public void test8(){
		//sorted() 產生一個新流,其中按天然順序排序(Comparable)
		List<String> list = Arrays.asList("aaa", "eee", "ccc","yyy");
		list.stream()
				.sorted()
				.forEach(System.out::print);//aaaccceeeyyy

		System.out.println("-----------------");
		//sorted(Comparator comp) 產生一個新流,其中按比較器順序排序(	Comparator)
		employees.stream()
				.sorted((e1,e2)->{
					if (e1.getAge() == e2.getAge()){
						return e1.getName().compareTo(e2.getName());
					}else{
						return Integer.compare(e1.getAge(), e2.getAge());
					}
				}).forEach(System.out::println);
	}

3. 終止操做

①查找與匹配

方法 描述
allMatch(Predicate p) 檢查是否匹配全部元素
anyMatch(Predicate p) 檢查是否至少匹配一個元素
noneMatch(Predicatep) 檢查是否沒有匹配全部元素
findFirst() 返回第一個元素
findAny() 返回當前流中的任意元素
count() 返回流中元素總數
max(Comparator c) 返回流中最大值
min(Comparator c) 返回流中最小值
forEach(Consumer c) 內部迭代(使用Collection 接口須要用戶去作迭代,稱爲外部迭代。相反,Stream API 使用內部迭代——它幫你把迭代作了)
/**
	 * 查找與匹配
	 * allMatch(Predicate p) 檢查是否匹配全部元素
	 anyMatch(Predicate p) 檢查是否至少匹配一個元素
	 noneMatch(Predicatep) 檢查是否沒有匹配全部元素
	 findFirst() 返回第一個元素
	 findAny() 返回當前流中的任意元素
	 count() 返回流中元素總數
	 max(Comparator c) 返回流中最大值
	 min(Comparator c) 返回流中最小值
	 forEach(Consumer c) 內部迭代(使用Collection 接口須要用戶去作迭代,稱爲外部迭代。相反,Stream API 使用內部迭代——它幫你把迭代作了)
	 */
	@Test
	public void test9(){
		boolean b1 = employees.stream()
				.allMatch(e -> e.getAge() > 20);
		System.out.println(b1);//false

		boolean b2 = employees.stream()
				.anyMatch(e -> e.getAge() > 20);
		System.out.println(b2);//true

		boolean b3 = employees.stream()
				.noneMatch(e -> e.getAge() > 20);
		System.out.println(b3);//false

		Optional<Employee>  op1 = employees.stream()
				.findFirst();
		System.out.println(op1.get());//Employee{name='張三', age=20}
		//並行流與串行流
		/*並行流就是把一個內容分紅多個數據塊,並用不一樣的線程分別處理每一個數據塊的流。
		Java 8 中將並行進行了優化,咱們能夠很容易的對數據進行並行操做。
		Stream API 能夠聲明性地經過parallel() 與sequential() 在並行流與順序流之間進行切換。*/
		Optional<Employee> op2 = employees.stream().parallel()
				.findAny();
		System.out.println(op2.get());//Employee{name='趙六', age=10}
		Optional<Employee> op3 = employees.stream().sequential()
				.findAny();
		System.out.println(op3.get());//Employee{name='張三', age=20}

		long num = employees.stream()
				.count();
		System.out.println(num);//8

		Optional<Employee> op4 = employees.stream()
				.max(Comparator.comparingInt(Employee:: getAge));
		System.out.println(op4.get());//Employee{name='李四', age=50}

		Optional<Employee> op5 = employees.stream()
				.min(Comparator.comparingInt(Employee:: getAge));
		System.out.println(op5.get());//Employee{name='李逵', age=4}
	}

②歸約

方法 描述
reduce(T iden, BinaryOperator b) 能夠將流中元素反覆結合起來,獲得一個值。返回T
reduce(BinaryOperator b) 能夠將流中元素反覆結合起來,獲得一個值。返回Optional<T>
/**
	 * 歸約
	 * reduce(T iden, BinaryOperator b) 能夠將流中元素反覆結合起來,獲得一個值。返回T
	 reduce(BinaryOperator b) 能夠將流中元素反覆結合起來,獲得一個值。返回Optional<T>
	 */
	@Test
	public void test10(){
		List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
		Integer sum = list.stream()
				.reduce(0, (x, y) -> x + y);
		System.out.println(sum); //21

		System.out.println("-----------------------------");

		Optional<Integer> op = employees.stream()
				.map(Employee:: getAge)
				.reduce(Integer:: sum);
		System.out.println(op.get());//212
	}

③收集

方法 描述
collect(Collector c) 將流轉換爲其餘形式。接收一個Collector接口的
實現,用於給Stream中元素作彙總的方法

Collector 接口中方法的實現決定了如何對流執行收集操做(如收集到List、Set、Map)。可是Collectors 實用類提供了不少靜態方法,能夠方便地建立常見收集器實例,具體方法與實例以下表:函數

方法   返回類型 做用
toList List<T> 把流中元素收集到List
List<Employee>emps=list.stream().collect(Collectors.toList());
toSet Set<T> 把流中元素收集到Set
Set<Employee>emps=list.stream().collect(Collectors.toSet());
toCollection Collection<T> 把流中元素收集到建立的集合
Collection<Employee>emps=list.stream().collect(Collectors.toCollection(ArrayList::new));
counting Long 計算流中元素的個數
long count=list.stream().collect(Collectors.counting());
summingInt Integer 對流中元素的整數屬性求和
inttotal=list.stream().collect(Collectors.summingInt(Employee::getSalary));
averagingInt Double 計算流中元素Integer屬性的平均值
doubleavg=list.stream().collect(Collectors.averagingInt(Employee::getSalary));
summarizingInt IntSummaryStatistics 收集流中Integer屬性的統計值。如:平均值
IntSummaryStatisticsiss=list.stream().collect(Collectors.summarizingInt(Employee::getSalary));
joining String 鏈接流中每一個字符串
Stringstr=list.stream().map(Employee::getName).collect(Collectors.joining());
maxBy Optional<T> 根據比較器選擇最大值
Optional<Emp>max=list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary)));
minBy Optional<T> 根據比較器選擇最小值
Optional<Emp>min=list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary)));
reducing 歸約產生的類型 從一個做爲累加器的初始值開始,利用BinaryOperator與流中元素逐個結合,從而歸約成單個值
inttotal=list.stream().collect(Collectors.reducing(0,Employee::getSalar,Integer::sum));
collectingAndThen 轉換函數返回的類型 包裹另外一個收集器,對其結果轉換函數
inthow=list.stream().collect(Collectors.collectingAndThen(Collectors.toList(),List::size));
groupingBy Map<K,List<T>> 根據某屬性值對流分組,屬性爲K,結果爲V
Map<Emp.Status, List<Emp>> map= list.stream().collect(Collectors.groupingBy(Employee::getStatus));
partitioningBy Map<Boolean,List<T>> 根據true或false進行分區
Map<Boolean,List<Emp>>vd=list.stream().collect(Collectors.partitioningBy(Employee::getManage));
/**
	 * 收集
	 * collect(Collector c) 將流轉換爲其餘形式。接收一個Collector接口實現,用於給Stream中元素作彙總的方法
	 */
	@Test
	public void test11(){
		List<String> list = employees.stream()
				.map(Employee:: getName)
				.collect(Collectors.toList());
		list.forEach(System.out::print);//張三李四王五王五王五趙六王琦李逵

		System.out.println("-----------------------");

		Set<String> set = employees.stream()
				.map(Employee:: getName)
				.collect(Collectors.toSet());
		set.forEach(System.out::print);//李四張三王琦王五趙六李逵

		System.out.println("-----------------------");

		HashSet hset = employees.stream()
				.map(Employee:: getName)
				.collect(Collectors.toCollection(HashSet::new));
		hset.forEach(System.out::print);//李四張三王琦王五趙六李逵
	}

	@Test
	public void test12(){
		//總數
		long count = employees.stream()
							.collect(Collectors.counting());
		System.out.println(count);//8
		//平均值
		Double avg = employees.stream()
				.collect(Collectors.averagingInt(Employee::getAge));
		System.out.println(avg);//26.5

		//總和
		int sum = employees.stream()
							.collect(Collectors.summingInt(Employee:: getAge));
		System.out.println(sum);//212
		//最大值
		Optional<Employee> max = employees.stream()
				.collect(Collectors.maxBy((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge())));
		System.out.println(max.get());//Employee{name='李四', age=50}
		//最小值
		Optional<Integer> min = employees.stream()
				.map(Employee:: getAge)
				.collect(Collectors.minBy(Integer:: compare));
		System.out.println(min.get());//4
	}
    //分組
	@Test
	public void test13(){
		Map<String,List<Employee>> map = employees.stream()
				.collect(Collectors.groupingBy(Employee:: getName));
		System.out.println(map.toString());
		/*{李四=[Employee{name='李四', age=50}],
		 張三=[Employee{name='張三', age=20}],
		 王琦=[Employee{name='王琦', age=8}],
		 王五=[Employee{name='王五', age=40}, Employee{name='王五', age=40}, Employee{name='王五', age=40}],
		 趙六=[Employee{name='趙六', age=10}],
		 李逵=[Employee{name='李逵', age=4}]}*/
	}

	//分區
	@Test
	public void test14() {
		Map<Boolean, List<Employee>> map = employees.stream()
				.collect(Collectors.partitioningBy((e) ->e.getAge() > 30));
		System.out.println(map);
		/*{
		false=[Employee{name='張三', age=20},
		       Employee{name='趙六', age=10},
		       Employee{name='王琦', age=8},
		       Employee{name='李逵', age=4}],
		 true=[Employee{name='李四', age=50},
		       Employee{name='王五', age=40},
		       Employee{name='王五', age=40},
		       Employee{name='王五', age=50}]}*/
	}

	//summarizingInt IntSummaryStatistics 收集流中Integer屬性的統計值。如:平均值
	@Test
	public void test15(){
		DoubleSummaryStatistics ds = employees.stream()
				.collect(Collectors.summarizingDouble(Employee:: getAge));
		System.out.println(ds.getAverage());//27.75
		System.out.println(ds.getCount());//8
		System.out.println(ds.getMax());//50.0
		System.out.println(ds.getMin());//4.0
		System.out.println(ds.getSum());//222.0
	}

	//joining鏈接流中每一個字符串
	@Test
	public void test16(){
		String str = employees.stream()
				.map(Employee:: getName)
				.collect(Collectors.joining(",", "---", "==="));
		System.out.println(str);//---張三,李四,王五,王五,王五,趙六,王琦,李逵===
	}
相關文章
相關標籤/搜索