前言
#博学谷IT学技术支持#
一、Stream流介绍
Java 8 新增的 Stream 是为了解放程序员操作集合(Collection)时的生产力,之所以能解放,很大一部分原因可以归功于同时出现的 Lambda 表达式——极大的提高了编程效率和程序可读性。
- stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果;
- stream不会改变数据源,通常情况下会产生一个新的集合;
- stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。
- 对stream操作分为终端操作和中间操作,那么这两者分别代表什么呢?
终端操作:会消费流,这种操作会产生一个结果的,如果一个流被消费过了,那它就不能被重用的。
中间操作:中间操作会产生另一个流。因此中间操作可以用来创建执行一系列动作的管道。一个特别需要注意的点是:中间操作不是立即发生的。相反,当在中间操作创建的新流上执行完终端操作后,中间操作指定的操作才会发生。所以中间操作是延迟发生的,中间操作的延迟行为主要是让流API能够更加高效地执行。 - stream不可复用,对一个已经进行过终端操作的流再次调用,会抛出异常。
二、创建流
- 使用 Collection 下的 stream() 和 parallelStream(), stream() 生成的是一个顺序流,parallelStream() 生成的是一个并行流
public class Main {
public static void main(String[] args) {
List<String> personList = new ArrayList<>();
Stream<String> stream = personList.stream();
Stream<String> parallelStream = personList.parallelStream();
}
}
- 使用 Arrays 中的 stream() 方法,将数组转成流
public class Main {
public static void main(String[] args) {
Integer[] nums = new Integer[10];
Stream<Integer> stream = Arrays.stream(nums);
}
}
- 使用 Stream 中的静态方法:of()、iterate()、generate()
public class Main {
public static void main(String[] args) {
Stream<Integer> streamOne = Stream.of(1, 2, 3, 4, 5, 6);
Stream<Integer> streamTwo = Stream.iterate(0, f -> f + 2).limit(6);
Stream<Double> streamThree = Stream.generate(Math::random).limit(2);
}
}
- 使用 BufferedReader.lines() 方法
public class Main {
public static void main(String[] args) throws FileNotFoundException {
BufferedReader bufferedReader = new BufferedReader(new FileReader("D:\\stream.txt"));
Stream<String> stream = bufferedReader.lines();
stream.forEach(System.out::println);
}
}
- 使用 Pattern.splitAsStream() 方法,将字符串分隔成流
public class Main {
public static void main(String[] args) {
Pattern pattern = Pattern.compile(",");
Stream<String> stream = pattern.splitAsStream("a,b,c,d");
stream.forEach(System.out::println);
}
}
三、操作流
Stream 类提供了很多有用的操作流的方法
public class Demo2 {
public static void main ( String[] args ) {
// 流的筛选
List<Integer> integerList = Arrays.asList(1, 2, 3,3, 4, 5, 6);
// 筛选出集合中数字大于4的元素
List<Integer> collect = integerList.stream().filter(x -> x > 4).collect(Collectors.toList());
System.out.println(collect); //[5, 6]
// 集合中的去重
List<Integer> collect1 = integerList.stream().distinct().collect(Collectors.toList());
System.out.println(collect1);//[1, 2, 3, 4, 5, 6]
// 获取流中的第一个元素
Optional<Integer> first = integerList.stream().filter(x -> x > 4).findFirst();
Optional<Integer> any = integerList.stream().filter(x -> x > 4).findAny();
Optional<Integer> any1 = integerList.parallelStream().filter(x -> x > 4).findAny();
System.out.println(first); //Optional[5]
System.out.println(any); //Optional[5]
System.out.println(any1); // 预期结果不稳定
}
}
四、映射
- map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
- flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
如下将给出一个示例来进行演示,代码如下
public class Main {
public static void main(String[] args) {
String[] words = {"Hello", "World"};
List<String[]> a = Arrays.stream(words)
.map(word -> word.split(""))
.distinct()
.collect(Collectors.toList());
a.forEach(System.out::println);
String[] wordsTwo = {"Hello", "World"};
List<String> b = Arrays.stream(wordsTwo)
.map(word -> word.split(""))
.flatMap(Arrays::stream)
.distinct()
.collect(Collectors.toList());
b.forEach(System.out::println);
}
}
五、Stream 流的终结操作方法
- allMatch:接收一个 Predicate 函数,当流中每个元素都符合该断言时才返回 true,否则返回 false。
- noneMatch:接收一个 Predicate 函数,当流中每个元素都不符合该断言时才返回 true,否则返回 false。
- anyMatch:接收一个 Predicate 函数,只要流中有一个元素满足该断言则返回 true,否则返回 false。
- findFirst:返回流中的第一个元素。
- findAny:返回流中的任意元素。
- count:返回流中元素的总个数。
- max:返回流中的元素最大值。
- min:返回流中的元素最小值。
- collect:进行收集、聚合等操作,返回(list,map,set等)特定类型。