【Java 8 新特性】Stream使用教程示例

【Java 8 新特性】Stream使用教程示例

  • 1.Streams vs Collections
  • 2.并行(`Parallel`)流和顺序(`Sequential`)流
  • 3.如何获取流(`Stream`)
  • 4.java.util.stream.Stream接口
    • 4.1.`Stream.allMatch()`, `Stream.anyMatch()`和`Stream.noneMatch()`
    • 4.2.`Stream.collect()`
    • 4.3.`Stream.concat()`
    • 4.4.`Stream.count()`
    • 4.5.`Stream.distinct()`
    • 4.6.`Stream.filter()`
    • 4.7.`Stream.findAny()`和`Stream.findFirst()`
    • 4.8.`Stream.flatMap()`
    • 4.9.`Stream.forEach()`和`Stream.forEachOrdered()`
    • 4.10.`Stream.generate()`和`Stream.limit()`
    • 4.11.`Stream.iterate()`
    • 4.12.`Stream.map()`
    • 4.13.`Stream.max()`和`Stream.min()`
    • 4.14.`Stream.peek()`
    • 4.15.`Stream.reduce()`
    • 4.16.`Stream.skip()`
    • 4.17.`Stream.sorted()`
    • 4.18.`Stream.toArray()`
  • 参考文献

本页将通过示例介绍 Java8 Stream使用方法。

Java8引入了一个包java.util.stream,它是由支持元素流上进行函数式操作的类组成。

这个包包含的基本类分别是Stream用于objects,以及IntStream, LongStream, DoubleStream分别用于原始数据类型integerlongdouble

java.util.stream.Stream是表示元素序列的接口。

它支持顺序和聚合操作。

计算过程由源操作、中间操作和终端操作组成流管道。

流是惰性的,流上的操作仅在终端操作启动时执行,源元素仅在需要时才被消耗。

在大多数流操作中,我们需要传递lambda表达式,该表达式必须是无干扰和无状态的。

无干扰意味着计算操作不修改源流,无状态意味着结果不应该依赖于流管道执行中可以改变的任何状态。

在流操作中传递的参数可以是java 8函数的实例或lambda表达式。

当调用中间或终端操作时,流应该只被操作一次,如果它被重用,它将抛出illeglastateException

流实现自动关闭,使用后不需要关闭,但如果流源是IO通道,则需要关闭它。

流由集合、数组或生成函数支持。

流可以顺序执行,也可以并行执行,这个选择是在最初创建流时做出的。

1.Streams vs Collections

流和集合有一些相似之处,但它们在许多方面有所不同。

  1. 集合有效地管理和允许访问元素,而流不允许直接操作或访问元素。流是使用创建新流的中间和终端操作计算的。
  2. 流不存储数据。它们只允许元素通过计算管道传递。流中元素的来源是数组、列表和映射。
  3. 流在本质上是功能性的。该函数应用于流的每个元素并生成结果,但不会修改源元素。
  4. 流操作通常分为中间操作和终端操作。中间操作总是懒惰的。
  5. 流是无界的,而集合的大小可以是有限的。无限的元素可以在有限时间内用流计算。
  6. 在计算中,流的元素在生命中只被访问一次。元素可以在流的另一个实例中重新访问,该实例将是上一个流实例上计算的输出。

2.并行(Parallel)流和顺序(Sequential)流

Java8流可以并行和顺序地计算。一个一个顺序地执行。在并行处理中,计算是同时进行的。

流内并行处理计算作为聚合操作的管道执行,而顺序流操作作为命令操作执行。

为了处理并行流和序列流,我们需要将流实例化为并行流和序列流,两者在编码上都是相同的。

我们可以实例化如下。

List<String> list = Arrays.asList("A", "B", "C");
list.stream(); //Sequential Stream
list.parallelStream(); //Parallel stream 

Collection还引入了新方法,即Collection.stream()Collection.parallelStream(),用于在我们的代码中获取顺序流和并行流。

3.如何获取流(Stream)

对于原始数据类型的流,java8提供IntStreamLongStreamDoubleStream类;

对于对象流,java8提供Stream类。有很多方法可以获得这些流的实例。

  1. 使用Collectionstream()parallelStream()方法,这些方法通过ListQueueSet等进行扩展。例如在List的情况下可以使用List.stream()List.parallelStream()方法
  2. Map的情况下使用Map.entrySet().stream()Map.entrySet().parallelStream()方法
  3. 使用Arrays.stream方法。我们可以将原始数据类型或对象的数组传递给这个方法,例如Arrays.stream(int[] array)Arrays.stream(Object[] array)等。
  4. 使用Stream.of(Object[] array).这里的of()Stream的静态方法。
  5. 原始数据类型流类还提供了获取流的方法,例如IntStream.range(int, int)等。
  6. 使用Stream.iterate(T seed, UnaryOperator f),其中T是元素的类型,f是应用于前一个元素以获取新元素的函数。
  7. 使用BufferedReader.lines().它返回字符串流。
  8. 使用Java8的Files方法,如find()lines()walk()`。这些方法返回流。
  9. 使用Random类可以得到原始数据类型的随机数流。Random类的ints()longs()doubles()方法分别返回IntStreamLongStreamDoubleStream
  10. 使用BitSet.stream(),我们得到索引流为IntStream
  11. 使用Pattern.splitAsStream(CharSequence input),我们得到字符串流。此方法为模式匹配项周围的给定输入序列创建流。
  12. JarFile.stream()返回ZIP文件项上的有序流。

4.java.util.stream.Stream接口

现在我们将在这里讨论java.util.stream.Stream接口。Stream类的方法接受函数实例或lambda表达式作为参数。

流的计算可以按顺序执行,也可以并行执行。

在一行代码中,我们可以对元素流执行聚合操作。

Stream方法的示例。

4.1.Stream.allMatch(), Stream.anyMatch()Stream.noneMatch()

allMatch():如果流的所有元素都与给定的Predicate匹配,则返回true
anyMatch():如果流的任何元素与给定Predicate匹配,则返回true
noneMatch():如果流中没有任何元素与给定Predicate匹配,则返回true

下面是示例代码

MatchElement.java

package com.concretepage;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class MatchElement {
     
	public static void main(String[] args) {
     
		Predicate<Integer> p = num -> num % 2 == 0;
		List<Integer> list = Arrays.asList(3,5,6);
		System.out.println("allMatch:" + list.stream().allMatch(p));
		System.out.println("anyMatch:" + list.stream().anyMatch(p));
		System.out.println("noneMatch:" + list.stream().noneMatch(p));
	}
}  

输出

allMatch:false
anyMatch:true
noneMatch:false 

4.2.Stream.collect()

java 8 Collector使用可使操作变得简单,下面是计算列表中整数和的例子。

StreamCollect.java

package com.concretepage;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StreamCollect {
     
	public static void main(String[] args) {
     
		List<Integer> list = Arrays.asList(3,5,6);
		int sum = list.stream().collect(Collectors.summingInt(i->i));
		System.out.println("Sum: "+ sum);
	}
}  

输出

Sum: 14 

4.3.Stream.concat()

它创建一个懒连接的流,包括第一个流的和下一个流的所有元素。

StreamConcat.java

package com.concretepage;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class StreamConcat {
     
	public static void main(String[] args) {
     
	    List<Integer> list1 = Arrays.asList(1,2,3);
            List<Integer> list2 = Arrays.asList(4,5,6);
            Stream<Integer> resStream = Stream.concat(list1.stream(), list2.stream());
            resStream.forEach(s->System.out.print(s+" "));
	}
}  

输出

1 2 3 4 5 6  

4.4.Stream.count()

它返回流中元素的数量。

StreamCount.java

package com.concretepage;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class StreamCount {
     
	public static void main(String[] args) {
     
		Predicate<Integer> p = num -> num % 2 == 0;
		List<Integer> list = Arrays.asList(3,4,6);
		System.out.println("Count: " + list.stream().filter(p).count());
	}
}  

输出

Count: 2 

4.5.Stream.distinct()

它返回具有不同元素的流。

StreamDistinct.java

package com.concretepage;
import java.util.Arrays;
import java.util.List;
public class StreamDistinct {
     
	public static void main(String[] args) {
     
		List<Integer> list = Arrays.asList(3,4,6,6,4);
		System.out.println("Distinct Count: " + list.stream().distinct().count());
	}
}  

输出

Distinct Count: 3 

4.6.Stream.filter()

它返回包含与给定Predicate匹配的元素的流。

StreamFilter.java

package com.concretepage;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class StreamFilter {
     
	public static void main(String[] args) {
     
		Predicate<Integer> p = num -> num % 2 == 0;
		List<Integer> list = Arrays.asList(3,4,6);
		list.stream().filter(p).forEach(e -> System.out.print(e+" "));
	}
}  

输出

4 6  

4.7.Stream.findAny()Stream.findFirst()

Stream.findAny():它可能返回流的任何元素。
Stream.findFirst():它返回流的第一个元素,如果流没有定义遇到顺序,那么它可以返回任何元素。

StreamFindAnyFindFirst.java

package com.concretepage;
import java.util.Arrays;
import java.util.List;
public class StreamFindAnyFindFirst {
     
	public static void main(String[] args) {
     
		List<String> list = Arrays.asList("G","B","F","E");
		String any = list.stream().findAny().get();
		System.out.println("FindAny: "+ any);
		String first = list.stream().findFirst().get();
		System.out.println("FindFirst: "+ first);		
	}
}  

输出

FindAny: G
FindFirst: G 

4.8.Stream.flatMap()

它在对每个元素应用映射函数后返回一个对象流,然后将结果展开。

StreamFlatMap.java

package com.concretepage;
import java.util.Arrays;
public class StreamFlatMap {
     
	public static void main(String[] args) {
     
		Integer[][] data = {
     {
     1,2},{
     3,4},{
     5,6}};
		Arrays.stream(data).flatMap(row -> Arrays.stream(row)).filter(num -> num%2 == 1)
		  .forEach(s -> System.out.print(s+" "));
	}

输出

1 3 5 

flatMapToInt():它与原始数据类型int一起使用并返回IntStream
flatMapToLong():它与基元数据类型long一起使用并返回LongStream
flatMapToDouble():它与基本数据类型double一起使用并返回DoubleStream

4.9.Stream.forEach()Stream.forEachOrdered()

forEach():它对流的每个元素执行一个操作。
forEachOrdered():它对流的每个元素执行一个操作,但如果定义了流,则按遇到的顺执行。

StreamForEach.java

package com.concretepage;
import java.util.Arrays;
public class StreamForEach {
     
	public static void main(String[] args) {
     
		Integer[] data = {
     1,2,3,4,5,6,7};
		System.out.println("---forEach Demo---");
		Arrays.stream(data).filter(num -> num%2 == 1)
		  .forEach(s -> System.out.print(s+" "));
		System.out.println("\n---forEachOrdered Demo---");		
		Arrays.stream(data).filter(num -> num%2 == 1)
		  .forEachOrdered(s -> System.out.print(s+" "));
	}
}  

输出

---forEach Demo---
1 3 5 7 
---forEachOrdered Demo---
1 3 5 7  

4.10.Stream.generate()Stream.limit()

generate():我们需要将Supplier传递给这个方法,它将返回一个无限连续的无序流。
limit():我们需要传递一个max值,它将返回最大元素数的流。

StreamGenerate.java

package com.concretepage;
import java.util.stream.Stream;
public class StreamGenerate {
     
	public static void main(String[] args) {
     
		String str = "Hello World!";
                Stream<String> stream = Stream.generate(str::toString).limit(5);
                stream.forEach(s->System.out.println(s));
	}
}  

输出

Hello World!
Hello World!
Hello World!
Hello World!
Hello World!

4.11.Stream.iterate()

我们需要将初始值和UnaryOperator传递给这个方法,它将返回一个无限连续的无序流。

StreamIterate.java

package com.concretepage;
import java.util.stream.Stream;
public class StreamIterate {
     
	public static void main(String[] args) {
     
	    Stream<Integer> stream = Stream.iterate(1, n  ->  n * 2).limit(5);
            stream.forEach(s->System.out.print(s+" "));
	}
}  

输出

1 2 4 8 16 

4.12.Stream.map()

它在对流的每个元素应用给定函数后返回一个流。

StreamMap.java

package com.concretepage;
import java.util.Arrays;
import java.util.List;
public class StreamMap {
     
	public static void main(String[] args) {
     
		List<Integer> list = Arrays.asList(1,2,3,4);
		list.stream().map(i -> i*i)
                  .forEach(s->System.out.print(s+" "));
	}
}  

输出

1 4 9 16 

mapToInt(): 它在应用给定函数后返回IntStream
mapToLong():它在应用给定函数后返回LongStream
mapToDouble():它在应用给定函数后返回DoubleStream

4.13.Stream.max()Stream.min()

max():它为给定的比较器(Comparator)查找最大元素。.
min():它为给定的比较器(Comparator)查找最小元素。

StreamMaxMin.java

package com.concretepage;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class StreamMaxMin {
     
	public static void main(String[] args) {
     
		List<String> list = Arrays.asList("G","B","F","E");
		String max = list.stream().max(Comparator.comparing(String::valueOf)).get();
		System.out.println("Max:"+ max);
		String min = list.stream().min(Comparator.comparing(String::valueOf)).get();
		System.out.println("Min:"+ min);		
	}
}  

输出

Max:G
Min:B 

4.14.Stream.peek()

这是一个中间操作。在应用使用者(Consumer)之后,它返回一个新的流,其中包含流的所有元素。

StreamPeek.java

package com.concretepage;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StreamPeek {
     
	public static void main(String[] args) {
     
            List<String> list = Arrays.asList("A","B","C");
            list.stream().peek(s->System.out.println(s+s)).collect(Collectors.toList());		
	}
}  

输出

AA
BB
CC 

4.15.Stream.reduce()

它使用起始值和累加函数对流元素执行缩减。

StreamReduce.java

package com.concretepage;
import java.util.Arrays;
public class StreamReduce {
     
	public static void main(String[] args) {
     
  	     int[] array = {
     3,5,10,15};
  	     int sum = Arrays.stream(array).reduce(0, (x,y) -> x+y);
  	     System.out.println("Sum:"+ sum);
	}
}  

输出

Sum:33 

4.16.Stream.skip()

它返回一个跳过给定数量元素的流。

StreamSkip.java

package com.concretepage;
import java.util.Arrays;
public class StreamSkip {
     
	public static void main(String[] args) {
     
  	     int[] array = {
     3,5,10,15};
  	     Arrays.stream(array).skip(2)
  	        .forEach(s -> System.out.println(s+ " "));
	}
}  

输出

10 
15 

4.17.Stream.sorted()

它返回一个用给定的比较器(Comparator)排序的流。

StreamSorted.java

package com.concretepage;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
public class StreamSorted {
     
	public static void main(String[] args) {
     
		Map<Integer, String> map = new HashMap<>();
		map.put(1, "BBBB");
		map.put(2, "AAAA");
		map.put(3, "CCCC");
		
		System.out.println("---Sort by Map Value---");
	        map.entrySet().stream().sorted(Comparator.comparing(Map.Entry::getValue))
	          .forEach(e -> System.out.println("Key: "+ e.getKey() +", Value: "+ e.getValue()));
	}
}  

输出

---Sort by Map Value---
Key: 2, Value: AAAA
Key: 1, Value: BBBB
Key: 3, Value: CCCC 

4.18.Stream.toArray()

它返回一个包含流元素的数组。

StreamToArray.java

package com.concretepage;
import java.util.Arrays;
import java.util.List;
public class StreamToArray {
     
	public static void main(String[] args) {
     
		List<String> list = Arrays.asList("A", "B", "C", "D");
		Object[] array = list.stream().toArray();
		System.out.println("Length of array: "+array.length);
	}
}  

输出

Length of array: 4 

参考文献

【1】Java Doc: Stream
【2】Java 8 Tutorials
【3】Java 8 Stream Tutorial with Example

你可能感兴趣的:(Java编程,#,Java,8,java,stream)