jdk8新特性Stream API
jdk8中新加入流Stream介面,主要為處理集合提供了便利,jdk8以後,在集合介面中新增加了預設的sream方法,用來生成流 物件結合Collection的原始碼增加的stream方法如下:
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
Stream可以看做是將流中的元素當作流水線上的產品來處理,比如一條傳送履帶,上面一個個元素傳過來,進行處理
目錄
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));
}
}