Java进阶之路 java8 流库
java8 API中文文档链接
在处理集合时,当我们需要遍历集合中元素,或者需要在每个元素时进行操作。列如,假设我们想要对某本书中的所有长单词进行计数。可以通过
var contents = new String(Files.readAllBytes(Paths.get("E:/1program/words.txt")),StandardCharsets.UTF_8); //从文件中读取数据
List<String> words = List.of(contents.split("\\PL+")); //通过正则表达式将其单词分为一个个字符串
int count = 0;
for (String w : words){
if(w.length() > 12)count++; //计数
}
在使用流之后,相同的操作看起来像下面这样:
var contents = new String(Files.readAllBytes(Paths.get("E:/1program/words.txt")),StandardCharsets.UTF_8); //从文件中读取数据
List<String> words = List.of(contents.split("\\PL+")); //通过正则表达式将其单词分为一个个字符串
long count = words.stream() //将list转化为流
.filter(w -> w.length() > 12) //lambda表达式
.count(); //计数
新的操作可读性很强,可以直接通过方法名确定这段代码意欲何为。此外,将stream()修改为parallelStream()可以并行的方式来执行过滤和计数。
long count = words.parallelStream()
.filter(w -> w.length() > 12)
.count();
这里写目录标题
一,流是什么
流是一类数据项,是一种可以让我们在更高的概念级别上指定计算任务的数据视图。
二,流的优点
流遵循了“做什么而非怎么做”的原则,它主要是对集合进行处理,它与集合相似,却有着显著的差异。
1,流并不储存元素。这些元素可能储存在底层的集合中,或者是按需生成的。
2,流的操作不会修改其数据源。当需要对数据进行处理时,会生成一个新的流包含修改后的元素。
3,流的操作是尽可能惰性执行的。这意味着直至需要其结果时,操作才会执行。
三,流的创建
1,通过Collection接口的stream方法将集合转化为一个流。
// default Stream<E> stream()
// default Stream<E> parallelStream()
// 产生当前集合中所有元素的顺序流或并行流
var contents = new String(Files.readAllBytes(Paths.get("E:/1program/words.txt")),StandardCharsets.UTF_8); //从文件中读取数据
List<String> words = List.of(contents.split("\\PL+"));
Stream<String> stream1 = words.stream();
Stream<String> stream2 = words.stream();
//还可以通过Array.stream(array, from, to) 可以用数组中的一部分元素来创建一个流。
2,通过静态的Stream.of方法。
//static <T> Stream<T> of(T... values>
//产生一个元素为定值的流。
var contents = new String(Files.readAllBytes(Paths.get("E:/1program/words.txt")),StandardCharsets.UTF_8);
Stream<String> stream = Stream.of(contents.split("\\PL+")); //split方法返回的为一个String数组
//of方法具有可变长参数,因此我们可以构建具有任意数量引元的流;
Stream<String> stream = Stream.of("gently", "down", "the", "stream");
3,通过Stream.empty方法。
//static <T> Stream<T> empty()
//产生一个不包含任何元素的流
Stream<String> stream = Stream.empty();
4,通过Stream.generate方法。
//static <T> Stream<T> generate(Supplier<T> s)
//产生一个无限流,它的值是通过反复调用函数s而构建的
Stream<String> stream1 = Stream.generate(() -> "Echo");
Stream<Double> stream2 = Stream.generate(Math::random);
//generate方法接受一个不包含任何引元的函数(及java8 函数式接口 Supplier<T>接口的对象)
5,通过Stream.iterate方法。
//static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)
//static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> f)
//产生一个无限流,他的元素包含 seed,在 seed上调用f产生的值,在前一个元素上调用f产生的值,等等。第一个方法会产生一个无限流,而第二个方法产生的流会在碰到第一个不满足hasNext的元素时终止。
Stream<BigInteger> integers = Stream.iterate(BigInteger.ZERO, n -> n.add(BigInteger.ONE));
//该序列中的一个元素时种子BigInteger.ZERO,第二个元素时f(seed),即1,下一个元素时f(f(seed)),即2,后续以此类推。
var limit = new BigInteger("100000");
Stream<BigInteger> stream = Stream.iterate(BigInteger.ZERO, n -> n.compareTo(limit) < 0, n -> n.add(BigInteger.ONE));
//第二个加了一个限制条件,n的最大值。
6,通过Stream.ofNullable方法。
//static <T> Stream<T> ofNummable(T t)
//如果t为null,返回一个空流,否则返回包含t的流。
var contents = new String(Files.readAllBytes(Paths.get("E:/1program/words.txt")),StandardCharsets.UTF_8);
Stream<String> stream1 = Stream.ofNullable(contents);
Stream<String> stream2 = Stream.ofNullable(null);
7,通过迭代器Spliterator的spliteratorUnknownSize方法
//static <T> Spliterator<T> spliteratorUnknownSize(Iterator<? extends T> iterator, int characteristics)
//用于给定的特性(一种包含诸如Spliterator.ORDERED之类的常量的位模式)将一个迭代器转换为一个具有未知尺寸可分割的迭代器。
Iterator<Path> iterator = Paths.get("E:/1program/words.txt").iterator()