1. 程式人生 > >JAVA8 Stream流

JAVA8 Stream流

什麼是Stream

流(Stream) 到底是什麼呢? 是資料渠道,用於操作資料來源(集合、陣列等)所生成的元素序列。“集合講的是資料,流講的是計算!” 注意: ①Stream 自己不會儲存元素。 ②Stream 不會改變源物件。相反,他們會返回一個持有結果的新Stream。 ③Stream 操作是延遲執行的。這意味著他們會等到需要結果的時候才執行。

Stream 的操作三個步驟

  • 建立Stream 一個數據源(如:集合、陣列),獲取一個流
  • 中間操作 一箇中間操作鏈,對資料來源的資料進行處理
  • 終止操作(終端操作) 一個終止操作,執行中間操作鏈,併產生結果 在這裡插入圖片描述

建立Stream

Java8 中的Collection 介面被擴充套件,提供了兩個獲取流的方法:

  • default Stream stream() : 返回一個順序流
  • default Stream parallelStream() : 返回一個並行流

由陣列建立流

Java8 中的Arrays 的靜態方法stream() 可以獲取陣列流:

  • static Stream stream(T[] array): 返回一個流 過載形式,能夠處理對應基本型別的陣列:
  • public static IntStream stream(int[] array)
  • public static LongStream stream(long[] array)
  • public static DoubleStream stream(double[] array)

由值建立流

可以使用靜態方法Stream.of(), 通過顯示值建立一個流。它可以接收任意數量的引數。

  • public static Stream of(T… values) : 返回一個流

由函式建立流:建立無限流 可以使用靜態方法Stream.iterate() 和Stream.generate(), 建立無限流。

  • 迭代 public static Stream iterate(final T seed, final UnaryOperator f)
  • 生成 public static Stream generate(Supplier s) :

多箇中間操作可以連線起來形成一個流水線,除非流水線上觸發終止操作,否則中間操作不會執行任何的處理! 而在終止操作時一次性全部處理,稱為“惰性求值”。

並行流與序列流

並行流就是把一個內容分成多個數據塊,並用不同的執行緒分別處理每個資料塊的流。 Java 8 中將並行進行了優化,我們可以很容易的對資料進行並行操作。Stream API 可以宣告性地通過parallel() 與sequential() 在並行流與順序流之間進行切換。

package da.test2.java8;

public class Employee {
	private int id;
	private String name;
	private int age;
	private double salary;
	private Status status;

	public Employee() {
		super();
	}

	public Employee(int id, String name, int age, double salary) {
		super();
		this.id = id;
		this.name = name;
		this.age = age;
		this.salary = salary;
	}

	public Employee(int id, String name, int age, double salary, Status status) {
		super();
		this.id = id;
		this.name = name;
		this.age = age;
		this.salary = salary;
		this.status = status;
	}

	public Employee(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}

	public Employee(String name) {
		super();
		this.name = name;
	}

	public Status getStatus() {
		return status;
	}

	public void setStatus(Status status) {
		this.status = status;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public double getSalary() {
		return salary;
	}

	public void setSalary(double salary) {
		this.salary = salary;
	}

	public String show() {
		return "測試方法引用!";
	}

	public String show(String str) {
		return "測試方法引用:" + str;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + id;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		long temp;
		temp = Double.doubleToLongBits(salary);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Employee other = (Employee) obj;
		if (age != other.age)
			return false;
		if (id != other.id)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		if (Double.doubleToLongBits(salary) != Double.doubleToLongBits(other.salary))
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "Employee [id=" + id + ", name=" + name + ", age=" + age + ", salary=" + salary + ", status=" + status
				+ "]";
	}

	public enum Status {
		FREE, BUSY, VOCATION;
	}
}
package da.test2.java8;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;

import org.junit.Test;

import da.test1.java8.Employee;

/*
 * 一、 Stream 的操作步驟
 * 
 * 1. 建立 Stream
 * 
 * 2. 中間操作
 * 
 * 3. 終止操作
 */
public class TestStreamAPI1 {
	// 1. 建立 Stream
	@Test
	public void test1() {
		// 1. Collection 提供了兩個方法 stream() 與 parallelStream()
		List<String> list = new ArrayList<String>();
		Stream<String> stream = list.stream(); // 獲取一個順序流
		Stream<String> parallelStream = list.parallelStream(); // 獲取一個並行流

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

		// 3. 通過 Stream 類中靜態方法 of()
		Stream<String> stream2 = Stream.of("aa", "bbb", "cccc");

		// 4. 建立無限流
		// 迭代
		Stream.iterate(0, x -> x + 2).limit(10).forEach(System.out::println);
		Stream<String> stream3 = Stream.iterate("aa", x -> x + "a").limit(10);
		stream3.forEach(System.out::println);

		// 生成
		Stream.generate(() -> (int) (Math.random() * 10)).limit(10).forEach(System.out::println);
		Stream.generate(Math::random).limit(10).forEach(System.out::println);

	}

	// 2. 中間操作
	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(105, "田七", 38, 5555.55), new Employee(105, "田七", 38, 5555.55),
			new Employee(105, "田七", 38, 5555.55));

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

	// 內部迭代:迭代操作 Stream API 內部完成
	@Test
	public void test2() {
		// 所有的中間操作不會做任何的處理
		Stream<Employee> stream = emps.stream().filter(e -> {
			System.out.println("中間引數測試");
			return e.getAge() >= 35;
		});
		// 只有當做終止操作時,所有的中間操作會一次性的全部執行,稱為“惰性求值”
		stream.forEach(System.out::println);
	}

	// 外部迭代
	@Test
	public void test3() {
		Iterator<Employee> it = emps.iterator();

		while (it.hasNext()) {
			System.out.println(it.next());
		}
	}

	@Test
	public void test4() {
		emps.stream().filter(e -> {
			System.out.println("短路!"); // && ||
			return e.getSalary() >= 5000;
		}).limit(2).forEach(System.out::println);
	}

	@Test
	public void test5() {
		emps.parallelStream().filter((e) -> e.getSalary() >= 5000).skip(2).forEach(System.out::println);
	}

	@Test
	public void test6() {
		emps.stream().distinct().forEach(System.out::println);
	}

	/*
	 * 對映
	 *
	 * map——接收 Lambda , 將元素轉換成其他形式或提取資訊。接收一個函式作為引數,該函式會被應用到每個元素上,並將其對映成一個新的元素。
	 * flatMap——接收一個函式作為引數,將流中的每個值都換成另一個流,然後把所有流連線成一個流
	 */
	@Test
	public void test7() {
		emps.stream().map(e -> e.getName()).distinct().forEach(System.out::println);

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

		List<String> strList = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
		strList.stream().map(String::toUpperCase).forEach(System.out::println);

		// Stream<Stream<Character>> stream = strList.stream().map(str ->
		// TestStreamAPI.filterCharacter(str));
		Stream<Stream<Character>> stream = strList.stream().map(TestStreamAPI1::filterCharacter);
		stream.forEach(s -> {
			s.forEach(System.out::println);
		});

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

		Stream<Character> stream2 = strList.stream().flatMap(TestStreamAPI1::filterCharacter);
		stream2.forEach(System.out::println);
	}

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

	@Test
	public void test8() {
		List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");

		List list2 = new ArrayList<>();
		list2.add("aa");
		list2.add("bb");
		// list2.add(list);
		list2.addAll(list);

		System.out.println(list2);
	}

	/*
	 * sorted()——自然排序
	 * 
	 * sorted(Comparator com)——定製排序
	 */
	@Test
	public void test9() {
		List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
		list.stream().sorted().forEach(System.out::println);

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

		emps.stream().map(Employee::getId).sorted().forEach(System.out::println);

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

		emps.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);
	}
}
package da.test2.java8;

import java.util.Arrays;
import java.util.DoubleSummaryStatistics;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.junit.Test;

import da.test2.java8.Employee.Status;

/*
 * 一、 Stream 的操作步驟
 * 
 * 1. 建立 Stream
 * 
 * 2. 中間操作
 * 
 * 3. 終止操作
 */
public class TestStreamAPI2 {
	List<Employee