1. 程式人生 > >jdk8新特性Stream API

jdk8新特性Stream API

jdk8中新加入流Stream介面,主要為處理集合提供了便利,jdk8以後,在集合介面中新增加了預設的sream方法,用來生成流 物件結合Collection的原始碼增加的stream方法如下:

default Stream<E> stream() {
        return StreamSupport.stream(spliterator(), false);
    }

Stream可以看做是將流中的元素當作流水線上的產品來處理,比如一條傳送履帶,上面一個個元素傳過來,進行處理 

目錄

Stream類 

常用的四種建立流的方式:

匹配方法:

建立流的方法

工具方法

map和reduce

收集方法

IntStream介面   

Optional類

OptionalInt類

OptionalDouble類

OptionalLong類

使用示例


Stream類 

常用的四種建立流的方式:

1使用靜態的of方法建立流

static<T> Stream<T> of(T... values)

如Stream<String> str = Stream.of("i","love","this","game");

Stream in=Stream.of(1,2,3,4,5)

2使用陣列來建立

Arrays工具類有多個建立流的流的方法:

比如:int [] intArr={1,2,3,4}

IntStream is=Arrays.stream(intArr)

3靜態方法iterate()建立無線流

static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)指定一個常量seed,產生從seed到常量f(由UnaryOperator指定方法得到)的流。這是一個無限迭代的過程。可以使用Stream的limit(long maxValue)方法指定需要的個數

例如:Stream s=Stream.iterate(1,i->i+1),返回一個i+1的流,1,2,3,.....

4通過集合的stream方法建立

因為Stream的增加主要是簡化了集合的操作,所以集合的實現類肯定有Stream方法了

用法如下 

List<Integer> list=new ArrayList<>(10);   Stream s=list.stream();

如果集合中全是某一個型別的元素,建立集合的時候最好傳入泛型,不然換成流後在流的方法中不能呼叫該型別的方法,因為流也不知道這種元素的型別是什麼

下面介紹Stream類的常用方法:

匹配方法:

boolean allMatch(Predicate<? super T> predicate) 返回是否所有元素都匹配過濾條件predicate,全部符合,返回true,否則false
boolean anyMatch(Predicate<? super T> predicate) 只要有一個元素複合傳入的匹配條件,返回true,全不復合,返回false

boolean noneMatch(Predicate<? super T> predicate) 判斷是否所有元素都不匹配指定規則,都不匹配返回true

建立流的方法

static <T> Stream.Builder<T> builder() 建立一個空的Stream.Builder流物件,可通過add方法新增元素,再通過StreamBuilder介面的build方法返回一個Stream型別的物件

static <T> Stream<T> empty() 返回一個空的Stream
static <T> Stream<T> iterate(T seed, UnaryOperator<T> f) ,通過指定seed值和指定方法生成限流,例如seed,f(seed),f(f(seed)),每次都巢狀上一次的值

static <T> Stream<T> generate(Supplier<T> s) 根據指定方法生成無限流,一般iterate和generate生成無限流,再配合limit方法可生成指定規則指定個數元素的流

static <T> Stream<T> of(T... values) ,靜態方法,根據給定可變引數生成流物件
static <T> Stream<T> of(T t) 生成單個元素的流物件


工具方法


static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) 將第一個流的元素和第二個流的元素拼接 
Optional<T> max(Comparator<? super T> comparator) 根據指定比較器返回流中最大值,為Optional型別
Optional<T> min(Comparator<? super T> comparator) 根據指定比較器返回流中最小值,為Optional型別
Stream<T> skip(long n) 跳過前n個元素,將後面的元素生成新的流. 
Stream<T> sorted() 按自然排序(升序)對流中每個元素進行排序後生成排序後的流
Stream<T> sorted(Comparator<? super T> comparator) 根據指定比較器進行排序,然後生成排序後的流,Comparator介面有實現的comparing方法,自然升序,如需降序,重寫compare方法,或者呼叫Integer或者String等類的compare方法,或者自己重寫

Stream<T> filter(Predicate<? super T> predicate) 根據指定規則過濾元素,通過規則的元素留下來生成新的Stream

Stream<T> limit(long maxSize) 指定要流的前maxSize個元素生成新的流
long count()  返回流中所有元素的個數 返回值為long型別
Stream<T> distinct()  找出流中相同的元素,並將重複元素過濾掉,就是去重,返回新的Stream

map和reduce

<R> Stream<R> map(Function<? super T,? extends R> mapper) 將流中每個元素經過指定方法或者改造後,重新生成一個新的流返回

IntStream mapToInt(ToIntFunction<? super T> mapper)將Stream中的元素通過指定方法後轉換為IntStream流,

DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper)將Stream中的元素通過指定方法後轉換為DoubleStream流

LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper)將Stream中的元素通過指定方法後轉換為LongStream流
 Optional<T> reduce(BinaryOperator<T> accumulator) 根據指定計算方法對流中所有元素計算,首先accumulator前兩個元素,第三個元素再與前兩個元素的計算記過accumulator,返回Optional型別

<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper) 將一個流中的每個元素都轉成一個流,然後再將這些流扁平化成為一個流

void forEach(Consumer<? super T> action)  迴圈遍歷


收集方法


Object[] toArray()  生成一個包含流中所有元素的陣列

<R,A> R collect(Collector<? super T,A,R> collector) 將流中所有元素收集到集合或者Map中

<R>R   collect(Supplier<R> supplier, BiConsumer<R,? super T> accumulator, BiConsumer<R,R> combiner) ,經過計算後再收集
上面提到collect方法需要的引數是Collector介面型別的,Collector是一個收集器,專門為collect方法設計,如果在API中沒找到的方法,基本在collect方法都可以實現,Collectors是一個工具類,提供了很多靜態方法,可以將Stream轉換為集合或Map(容器中的Map)

比如collect(Collectors.toList)將Stream轉換為List

 

IntStream介面   

在java.util.stream包下,IntStream主要來處理數值型資料,相比Stream增加了幾個方法,簡單介紹下

int sum()求流中所有元素的和

OptionalInt min()找出流中最小的元素的值

OptionalInt max()找出流中最大的元素的值

OptionalDouble average()求流中所有元素的平均值

static IntStream range(int startInclusive, int endExclusive)生成一個數值流,在兩個引數之間,包括第一個引數,不包括第二個引數

static IntStream rangeClosed(int startInclusive, int endInclusive)生成一個數值流,在兩個引數之間,包括第一個引數,也包括第二個引數

相似的介面還有DoubleStream,LongStream

Optional類

java.util.Optional Optinal類主要是防止出現空指標異常,省去了非空指標判斷

常用方法:使用Optional時,跟Stream一樣,如果沒指定泛型,則在Optional的方法中不能直接使用該類的方法,因為它不能自動識別值屬於哪個類

static <T> Optional<T> empty() 建立一個空的Optional例項

static <T> Optional<T> ofNullable(T value) 若value不為null,建立Optional例項,否則建立空例項

static <T> Optional<T> of(T value)  根據指定非空值建立Optional物件,最好配合orElse()方法使用

T orElse(T other)如果Optional物件的值存在,返回值,如果不存在,為空,則返回指定值

T get() 得到optional物件的值
void ifPresent(Consumer<? super T> consumer) 如果Optional物件的值存在,根據消費者介面的方法處理,如不存在,什麼也不做

Optional<T> filter(Predicate<? super T> predicate) 如果Optionla物件的值存在,根據指定規則處理後返回Optional例項,值不存在就返回空的Optional例項
boolean isPresent() 判斷值是否存在
<U> Optional<U> map(Function<? super T,? extends U> mapper) 存過值存在,對齊處理,如果處理後的結果存在返回Optional例項

OptionalInt類

int getAsInt()得到optinalInt型別的值

OptionalDouble類

double getAsDouble()得到optinalDouble型別的值

OptionalLong類

long getAsLong()得到optinalLong型別的值

使用示例

為了方便,先提供一個自定義的建立集合的類:


import java.util.ArrayList;
import java.util.List;

public class Student {
	private int age;

	public Student(int age, String name) {
		super();
		this.age = age;
		this.name = name;
	}

	@Override
	public String toString() {
		return "Student [age=" + age + ", name=" + name + "]";
	}

	public int getAge() {
		return age;
	}

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

	public String getName() {
		return name;
	}

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

	private String name;

}

class GereStuList {
	public static List generate() {
		List<Student> list = new ArrayList<>(10);
		list.add(new Student(12, "張三"));
		list.add(new Student(13, "朱十"));
		list.add(new Student(14, "石二"));
		list.add(new Student(15, "謝九"));
		list.add(new Student(16, "何八"));
		list.add(new Student(17, "劉七"));
		list.add(new Student(18, "鄭一"));
		list.add(new Student(19, "趙六"));
		list.add(new Student(20, "王五"));
		list.add(new Student(21, "李四"));
		return list;

	}
}

:演示Stream的使用:

import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamTest01 {

	public static void main(String[] args) {
		Stream s = Stream.of(1, 2, 3, 4, 5);
		// iterate生成Stream[1,2,3,4,5]
		Stream s0 = Stream.iterate(1, i -> i + 1).limit(5);
		s0.forEach(System.out::println);

		List<Student> list = GereStuList.generate();

		// 將list中的Student按年齡大於等於15的,升序排列,列印
		// 呼叫compare中的排序方法comparing自然排序
		list.stream().filter(x -> x.getAge() >= 15).sorted(Comparator.comparing(Student::getAge))
				.forEach(x -> System.out.println(x));

		// 將list中的Student年齡小於15的,降序排列列印
		// 呼叫Integer中的compare方法
		list.stream().filter(x -> x.getAge() < 15).sorted((s1, s2) -> Integer.compare(s2.getAge(), s1.getAge()))
				.forEach(System.out::println);

		// 計算list中年齡小於16的元素的個數
		long count = list.stream().filter(x -> x.getAge() < 16).count();
		System.out.println(count);

		// 取出每個人的年齡,加1後返回成List
		List list2 = list.stream().map(x -> x.getAge()).map(i -> i + 1).collect(Collectors.toList());
		list2.forEach(System.out::println);

		// 獲取List中每個人的名字,返回成一個List
		list2 = list.stream().map(x -> x.getName()).collect(Collectors.toList());
		list2.forEach(System.out::println);

		// 計算list中大於16的人的年齡之和
		Optional sum = list.stream().filter(x -> x.getAge() > 16).map(x -> x.getAge()).reduce((x, y) -> x + y);
		System.out.println(sum);

		// 將list中大於16的人的年齡各減1,再計算他們的年齡之和
		int sum2 = list.stream().filter(x -> x.getAge() > 16).map(x -> x.getAge() - 1).reduce(0, (x, y) -> x + y);
		System.out.println(sum2);

		// 返回最大年齡和最小年齡
		Optional o1 = list.stream().map(x -> x.getAge()).max((x, y) -> Integer.compare(x, y));
		System.out.println(o1);
		o1 = list.stream().map(x -> x.getAge()).max((x, y) -> Integer.compare(y, x));
		System.out.println(o1);

		// 計算最大年齡和最小年齡
		Optional o2 = list.stream().map(x -> x.getAge()).reduce((x, y) -> Integer.max(x, y));
		System.out.println(o2);
		o2 = list.stream().map(x -> x.getAge()).reduce(Integer::min);// 使用了Integer中的min方法
		System.out.print(o2);

	}
}

演示IntStream的使用:

import java.util.List;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.stream.IntStream;

public class IntStreamTest02 {
	public static void main(String[] args) {
		List<Student> list = GereStuList.generate();
		// 將stream流中的學生年齡抽取出來轉換為IntStream流,並計算所有學生年齡之和
		int i1 = list.stream().mapToInt(Student::getAge).sum();
		System.out.println(i1);
		int i2 = list.stream().mapToInt(x -> x.getAge()).sum();
		System.out.println(i2);
		// 計算學生平均年齡
		OptionalDouble ave = list.stream().mapToInt(x -> x.getAge()).average();
		System.out.println(ave);
		// 計算學生中年齡最大的值
		OptionalInt max = list.stream().mapToInt(x -> x.getAge()).max();
		System.out.println(max);
		// 生成0-50之間的數,包括50
		IntStream is = IntStream.rangeClosed(0, 50);
		is.forEach(System.out::println);
		// 計算0-52之間(不包括52)能被3整除的元素個數
		long count = IntStream.range(0, 52).filter(i -> i % 3 == 0).count();
		System.out.println(count);
	}
}

optional示例:

import java.util.List;
import java.util.Optional;

import stream.Student;

public class OptionalTest01 {
	public static void main(String[] args) {
		List<Student> list = GenerateStudentList.generate();
		// 計算學生中年齡大於30的人的年齡之和
		Optional op = list.stream().filter(x -> x.getAge() > 30).map(x -> x.getAge()).reduce((x, y) -> x + y);
		System.out.println(op);// 打印出了Optional.empty,我們知道list中的學生年齡沒有大於30的
		System.out.println(op.orElse(0));// 打印出了0

		Student s1 = new Student(10, "張三丰");
		s1 = null;
		// 現在我們知道s1的指向為空,如果直接呼叫其方法,肯定會報空指標異常
		Optional<Student> stuop = Optional.ofNullable(s1);
		System.out.println(stuop);// 打印出Optional.empty
		// 呼叫Optional重新的ifPresent方法,如果值存在,就對其處理
		stuop.ifPresent(x -> System.out.println(x.getAge()));// 因為沒有值存在,什麼也不做
		// 如果不設定泛型,使用orElse方法時不會要求傳入指定型別的值,Object型別就可以了,但Optional方法中也不能使用該指定型別的值
		System.out.println(stuop.orElse(new Student(50, "小二黑")));

		// 再來看個字串
		String s2 = "hello";
		s1 = null;
		Optional op2 = Optional.ofNullable(s1);

		System.out.println(op2.orElse(15));

	}
}