在学习Java Stream API以前,让咱们看看为何须要它。假设咱们须要遍历一个整数列表,并找出全部大于10的整数之和。编程
在Java 8以前,咱们会这样写:数组
private static int sumIterator(List<Integer> list) {
int sum = 0;
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
int item = iterator.next();
if (item > 10) {
sum += item;
}
}
return sum;
}
复制代码
上述方法存在三个主要问题:数据结构
为了克服上述全部缺点,引入了Java 8 Stream API。 咱们可使用Java Stream API来实现内部迭代,这样会更好,由于Java在帮咱们控制着迭代。app
内部迭代提供了一些功能,例如顺序和并行执行,基于给定条件的过滤,映射等。框架
大多数Java 8 Stream API方法参数都是函数式接口,所以lambda
表达式能够很好地与它们一块儿使用。 让咱们看看如何使用Java Stream 在单行语句中编写以上逻辑。less
private static int sumIterator(List<Integer> list) {
return list.stream().filter(i -> i > 10).mapToInt(i -> i).sum();
}
复制代码
以上程序利用了Java框架的迭代,过滤,和映射方法,提升了效率。ide
首先,咱们将研究Java 8 Stream API的核心概念,而后咱们将经过一些示例来了解最经常使用的方法。函数
集合是用于保存值的内存数据结构,在开始使用集合以前,全部值都应已填充。 而Java Stream是按需计算的数据结构。post
Java Stream 不存储数据,而是对源数据结构(集合和数组)进行操做,并生成可使用并执行特定操做的流水线数据。 例如,咱们能够从列表建立流并根据条件对其进行过滤。
Java Stream 操做使用函数式接口,这使其很是适合使用lambda表达式的功能编程。 如您在上面的示例中看到的那样,使用lambda表达式使咱们的代码可读性强且简短。
Java 8 Stream内部迭代原理有助于实现某些流操做中的延迟查找。 例如,能够延迟实施过滤,映射或重复删除,从而实现更高的性能和优化范围。
Java stream 流是可消耗的,所以没法建立流引用以供未来使用。 因为数据是按需提供的,所以没法屡次重复使用同一数据流。
Java 8 Stream支持顺序以及并行处理,并行处理对于实现大型集合的高性能很是有帮助。
全部Java Stream API接口和类都在java.util.stream包中。 因为咱们可使用自动装箱在集合中使用int之类的原始数据类型,而且这些操做可能会花费不少时间,所以有一些针对原始类型的特定类-IntStream,LongStream和DoubleStream。
Java 8 Stream API方法中一些经常使用的功能接口是:
Function表示一个函数,它接受一种类型的参数并返回另外一种类型的参数。 Function <T,R>是通用形式,其中T是函数输入的类型,R是函数结果的类型。
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
复制代码
BiFunction表示一个函数,它接受两种类型的参数并返回另外一种类型的参数。 Function <T,U,R>是通用形式,其中T,U是函数输入的类型,R是函数结果的类型。
@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T t, U u);
}
复制代码
为了处理原始类型,有特定的函数接口-ToIntFunction
,ToLongFunction
,ToDoubleFunction
,ToIntBiFunction
,ToLongBiFunction
,ToDoubleBiFunction
,LongToIntFunction
,LongToDoubleFunction
,IntToLongFunction
,IntToDoubleFunction
等。
使用Function
或原始类型转化相关的Function
接口的Stream方法包括:
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
IntStream mapToInt(ToIntFunction<? super T> mapper);
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
<A> A[] toArray(IntFunction<A[]> generator);
<U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner);
复制代码
Predicate表示一个函数,它接受一种类型的参数,返回一个布尔值,用于从Java Stream中过滤元素
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
复制代码
和Function
同样,为了处理原始类型,它也有特定的函数接口-IntPredicate
, DoubePredicate
, LongPredicate
使用Predicate或BiPredicate做为参数的一些Stream方法是:
Stream<T> filter(Predicate<? super T> predicate);
boolean anyMatch(Predicate<? super T> predicate);
boolean anyMatch(Predicate<? super T> predicate);
boolean noneMatch(Predicate<? super T> predicate);
复制代码
Consumer表示一个接受单个输入参数且不返回结果的操做。 它可用于对Java Stream的全部元素执行某些操做。
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
复制代码
使用Consumer,BiConsumer做为参数的Java 8 Stream方法包括:
Stream<T> peek(Consumer<? super T> action);
void forEach(Consumer<? super T> action);
void forEachOrdered(Consumer<? super T> action);
复制代码
Supplier表明一种操做,经过该操做咱们能够在流中生成新值。
@FunctionalInterface
public interface Supplier<T> {
T get();
}
复制代码
Stream中带有Supplier参数的一些方法是:
public static<T> Stream<T> generate(Supplier<T> s) <R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner);
复制代码
Java Optional是一个容器对象,可能包含也可能不包含非null值。 若是存在值,则isPresent() 将返回true,而get()将返回该值。 流终端操做
返回Optional对象。 其中一些方法是:
Optional<T> reduce(BinaryOperator<T> accumulator) Optional<T> min(Comparator<? super T> comparator) Optional<T> max(Comparator<? super T> comparator) Optional<T> findFirst() Optional<T> findAny() 复制代码
中间操做: 返回新Stream的Java Stream API操做称为中间操做。 在大多数状况下,这些操做本质上都是惰性的,所以中间操做只在终端操做出现时才会执行。 中间操做不会生成最终结果。 经常使用的中间操做是filter
和map
。
终端操做:返回结果或产生反作用的Java 8 Stream API操做。 一旦在流上调用了终端方法,该流就会被消耗,此后咱们将没法使用该流。 终端操做会在返回结果以前处理流中的全部元素。 经常使用的终端方法是forEach
,toArray
,min
,max
,findFirst
,anyMatch
,allMatch
等。您能够从返回类型中识别终端方法,它们永远不会返回Stream。
对于一个 intermediate 操做,若是它接受的是一个无限大(infinite/unbounded)的 Stream,但返回一个有限的新 Stream。例如limit()和skip()是两个短路中间操做
对于一个 terminal 操做,若是它接受的是一个无限大的 Stream,但能在有限的时间计算出结果。 例如anyMatch
,allMatch
,noneMatch
,findFirst
和findAny
是短路终端操做。
咱们能够经过几种方法从数组和集合建立Java流。 让咱们用简单的例子来研究它们。
Stream<Integer> stream = Stream.of(1,2,3,4);
复制代码
Stream<Integer> stream = Stream.of(new Integer[]{1,2,3,4});
//works fine
Stream<Integer> stream1 = Stream.of(new int[]{1,2,3,4});
//Compile time error, Type mismatch: cannot convert from Stream<int[]> to Stream<Integer>
复制代码
List<Integer> myList = new ArrayList<>();
for(int i=0; i<100; i++) myList.add(i);
//sequential stream
Stream<Integer> sequentialStream = myList.stream();
//parallel stream
Stream<Integer> parallelStream = myList.parallelStream();
复制代码
Stream<String> stream1 = Stream.generate(() -> {return "abc";});
Stream<String> stream2 = Stream.iterate("abc", (i) -> i);
复制代码
LongStream is = Arrays.stream(new long[]{1,2,3,4});
IntStream is2 = "abc".chars();
复制代码
Stream<Integer> intStream = Stream.of(1,2,3,4);
List<Integer> intList = intStream.collect(Collectors.toList());
System.out.println(intList); //prints [1, 2, 3, 4]
intStream = Stream.of(1,2,3,4); //stream is closed, so we need to create it again
Map<Integer,Integer> intMap = intStream.collect(Collectors.toMap(i -> i, i -> i+10));
System.out.println(intMap); //prints {1=11, 2=12, 3=13, 4=14}
复制代码
Stream<Integer> intStream = Stream.of(1,2,3,4);
Integer[] intArray = intStream.toArray(Integer[]::new);
System.out.println(Arrays.toString(intArray)); //prints [1, 2, 3, 4]
复制代码
List<Integer> myList = new ArrayList<>();
for(int i=0; i<100; i++) myList.add(i);
Stream<Integer> sequentialStream = myList.stream();
Stream<Integer> highNums = sequentialStream.filter(p -> p > 90); //filter numbers greater than 90
System.out.print("High Nums greater than 90=");
highNums.forEach(p -> System.out.print(p+" "));
//prints "High Nums greater than 90=91 92 93 94 95 96 97 98 99 "
复制代码
Stream<String> names = Stream.of("aBc", "d", "ef");
System.out.println(names.map(s -> {
return s.toUpperCase();
}).collect(Collectors.toList()));
//prints [ABC, D, EF]
复制代码
Stream<String> names2 = Stream.of("aBc", "d", "ef", "123456");
List<String> reverseSorted = names2.sorted(Comparator.reverseOrder()).collect(Collectors.toList());
System.out.println(reverseSorted); // [ef, d, aBc, 123456]
Stream<String> names3 = Stream.of("aBc", "d", "ef", "123456");
List<String> naturalSorted = names3.sorted().collect(Collectors.toList());
System.out.println(naturalSorted); //[123456, aBc, d, ef]
复制代码
Stream<List<Integer>> inputStream = Stream.of(
Arrays.asList(1),
Arrays.asList(2, 3),
Arrays.asList(4, 5, 6)
);
Stream<Integer> outputStream = inputStream.
flatMap((childList) -> childList.stream());
System.out.println(outputStream.collect(Collectors.toList()));
// [1, 2, 3, 4, 5, 6]
复制代码
Integer sum = integers.reduce(0, (a, b) -> a+b);
// 或
Integer sum = integers.reduce(0, Integer::sum);
复制代码
也存在没有起始值的状况,这时会把 Stream 的前面两个元素组合起来,返回的是 Optional。
// 字符串链接,concat = "ABCD"
String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat);
// 求最小值,minValue = -3.0
double minValue = Stream.of(-1.5, 1.0, -3.0, -2.0).reduce(Double.MAX_VALUE, Double::min);
// 求和,sumValue = 10, 有起始值, 起始值为10
int sumValue = Stream.of(1, 2, 3, 4).reduce(10, Integer::sum);
// 求和,sumValue = 10, 无起始值
sumValue = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
// 过滤,字符串链接,concat = "ace"
concat = Stream.of("a", "B", "c", "D", "e", "F").
filter(x -> x.compareTo("Z") > 0).
reduce("", String::concat);
复制代码
Stream<Integer> numbers1 = Stream.of(1,2,3,4,5);
System.out.println("Number of elements in stream="+numbers1.count()); //5
复制代码
Stream<Integer> numbers2 = Stream.of(1,2,3,4,5);
numbers2.forEach(i -> System.out.print(i+",")); //1,2,3,4,5,
复制代码
Stream<Integer> numbers3 = Stream.of(1,2,3,4,5);
System.out.println("Stream contains 4? "+numbers3.anyMatch(i -> i==4));
//Stream contains 4? true
Stream<Integer> numbers4 = Stream.of(1,2,3,4,5);
System.out.println("Stream contains all elements less than 10? "+numbers4.allMatch(i -> i<10));
//Stream contains all elements less than 10? true
Stream<Integer> numbers5 = Stream.of(1,2,3,4,5);
System.out.println("Stream doesn't contain 10? "+numbers5.noneMatch(i -> i==10));
//Stream doesn't contain 10? true
复制代码