最基本的流的创建方法就是
Stream.of(一组条目)
Collection.stream()
我们可以把任意相同类型的一组条目写在Stream.of()
的参数中使之变成一个流,比如:
Stream.of("a", "b", "c", "d"); Stream.of(new Node(1), new Node(2), new Node(3)); Stream.of(1, 2, 3, 4, 5);
而Collection
接口的stream()
方法则更是我们的好伙伴,所有实现了该接口的集合,都可以直接转变为一个流由我们处理。
此外,我们还有以下生成流的手段
int
基本类型的区间范围方法generate()
方法iterate()
方法Arrays.stream()
将数组转换为流下面来逐一了解
随机数流
Random
类已经得到了增强,现在有一组可以生成流的方法。
ints()
longs()
doubles()
boxed()
可以清楚的看到,我们只能通过Random
类获取三种基本类型的流,或者在其后加上boxed()
来获取它们的包装类的流。实际上,Random
类生成的这些数值,还有别的价值,比如通过随机数来获取某个列表中的随机下表对应值,以此来获取随机的对象。
int区间范围方法
IntStraem
类提供了新的range()
方法,可以生成一个流,它代表一个由int
值组成的序列,对于IntStream.range(a, b)
来说,这个流中的数据是[a, b)
区间的所有整数。
利用这个方法,我们可以通过流很好的代替某些循环了,比如:
public class Repeat{ public static repeat(int n, Runnable action){ IntStream.range(0, n).forEach(i -> action.run()); } }
这样一个方法就是把我们的action
方法执行n
次,可以很好的替代普通的循环。
generate() 方法
Stream.generate()
方法可以接受一个方法作为参数,该方法必须要返回一个实例或基本类型。总之,无论你给出的方法返回了什么,generate()
方法会无限的根据该方法产生元素并塞入流中,如果你不希望它无限产生,那么你应该使用limit()
来限制次数
AtomicInteger i = new AtomicInteger(); Stream.generate(() -> i.getAndIncrement()) .limit(20) .forEach(System.out::println); // 输出为从0到19
iterate()方法
顾名思义,这个方法通过迭代不断产生元素,它可以将第一个参数作为输入赋给第二个参数 (也就是那个方法),然后该方法会产生一个输出,随后该输出又会作为输入再度交给方法来产生下一个输出,由此不断迭代。一个典型的例子是由此产生一个斐波那契数列的方法,如下所示。
int x = 0; public Stream<Integer> numbers(){ return Stream.iterate(1, o ->{ int result = o + x; x = o; return result; }); } public static void main(String[] args) { test2 t = new test2(); t.numbers() .limit(20) .forEach(System.out::println); }
流生成器
流生成器方法Stream.builder()
可以返回Stream.Builder<T>
类,你可以自定义这个返回的类的泛型以便适配需求,随后,你可以将它当作一个类似StringBuilder
一样的存在使用,通过add()
等方法向里面塞入元素,并最终通过build()
方法来返回一个流。
Stream.Builder<String> builder = Stream.builder(); builder.add("a").add("b").add("c").build() .map(x -> x.toUpperCase()) .forEach(System.out::print); // 输出ABC
Arrays流方法
Arrays.stream()
静态方法可以将一个数组转化为流,非常简单易理解
int[] chars = {1,2,3,4,5}; Arrays.stream(chars) .forEach(System.out::print); // 输出12345
正则表达式
Java 8在java.util.regex.Pattern
类中加入了一个新方法splitAsStream()
,该方法接受一个字符序列并可以根据我们传入的公式将其分拆为一个流。
要注意的是,这个地方的输入不能直接是一个流,必须得是一个CharSequence
String s = "abcdefg"; Pattern.compile("[be]").splitAsStream(s) .map(x -> x+"?") .forEach(System.out::print); // 输出a?cd?fg?
我们获取了流,那么我们要做什么呢?显然,我们希望逐个对流中的数据进行操作,我们有以下方式可选:
peek()
sorted()
sorted(Comparator compa)
distinct()
filter(Predicate)
map(Function func)
mapToInt(ToIntFunction func)
mapToLong(ToLongFunction func)
mapToDouble(ToDoubleFunction func)
flatMap(Function func)
flatMapToInt(ToIntFunction func)
flatMapToLong(ToLongFunction func)
flatMapToDouble(ToDoubleFunction func)