流(Stream)作为JAVA8新特性之一,主要是提供了一种声明性处理数据集的方法来操作集合和数组元素,并且提供了大量包括数据的转换、筛选、聚合等操作在内的API,极大的简化了对于数据的处理,让开发者可以以更高效、更可读的方式编写代码。
1. 特点
- 惰性求值:Stream 的操作是延迟执行的,只有在需要结果时才会执行。
- 有序性:流保持其元素的有序性,除非显式地使用无序操作。
- 可并行化:Stream API 支持并行处理,可以充分利用多核处理器的优势。
- 不可变性:流操作不会修改其数据源中的元素,而是生成新的流。
2.使用步骤
以下是使用Stream的一般步骤:
- 获取一个数据源(如List、Set、数组等)。
- 调用
stream()
方法获取数据流。 - 使用各种中间操作对数据流进行处理(如筛选、转换等)。
- 调用终端操作执行对数据流的最终处理(如聚合、收集结果等)。
其中最重要的是第三步和第四布当中对于数据的处理和数据的收集,这里根据是对数据进行中间处理和最终收集将流操作分为了中间操作和终端操作,下面将会对这些操作进行详细的讲解:
2.1中间操作
中间操作返回一个新的 Stream,允许多个操作链式调用。常见的中间操作包括 filter
、map
、sorted
、distinct
、limit
、skip
等。
2.1.1 filter
filter
方法用于对 Stream 中的元素进行过滤,保留满足条件的元素。
public class Main {
public static void main(String[] args) {
ArrayList<Integer> integers = new ArrayList<>();
integers.add(1);
integers.add(2);
integers.add(3);
integers.stream().filter(i-> i>2).forEach(System.out::println);
}
}
2.1.2 map
map
方法用于对 Stream 中的每个元素应用一个函数,并将其映射成新的元素。
这里涉及到了JAVA8中另外一个新特性—lambda表达式函数式编程,可以自行查阅。
public class Main {
public static void main(String[] args) {
ArrayList<Integer> integers = new ArrayList<>();
integers.add(1);
integers.add(2);
integers.add(3);
integers.stream().map(i->i+1).forEach(System.out::println);
}
}
2.1.3 sorted
sorted
方法用于对 Stream 中的元素进行排序,默认是自然顺序,也可以传入自定义比较器。
public class Main {
public static void main(String[] args) {
ArrayList<Integer> integers = new ArrayList<>();
integers.add(2);
integers.add(1);
integers.add(3);
integers.stream().sorted().forEach(System.out::println);
}
}
2.1.4 distinct
distinct
用于去除流中的重复元素,只保留唯一的元素。
public class Main {
public static void main(String[] args) {
ArrayList<Integer> integers = new ArrayList<>();
integers.add(2);
integers.add(3);
integers.add(3);
integers.stream().distinct().forEach(System.out::println);
}
}
2.2 终端操作
终端操作会触发 Stream 的计算,并生成一个结果。常见的终端操作包括 forEach
、collect
、reduce
、count
、anyMatch
、allMatch
、noneMatch
、findFirst
、findAny
等。
2.2.1 collect
collect
方法用于将 Stream 中的元素收集到一个集合或其他容器中。
collect方法支持一个参数,这个参数是一个Collector工具类,想了解的朋友看看这个:
玩转Java8的 Stream 之Collectors收集器
public class Main {
public static void main(String[] args) {
ArrayList<Integer> integers = new ArrayList<>();
integers.add(2);
integers.add(3);
integers.add(3);
integers.stream().collect(Collectors.toList()).forEach(System.out::println);
Long collect = integers.stream().distinct().collect(Collectors.counting());
System.out.println(collect);
}
}
2.2.2 forEach
forEach
方法用于对 Stream 中的每个元素执行一个动作。
public class Main {
public static void main(String[] args) {
List<String> items = Arrays.asList("apple", "banana", "cherry");
items.stream()
.forEach(System.out::println);
}
}
2.2.3 reduce
reduce
方法用于将 Stream 中的元素组合起来,生成一个值。它可以用于实现求和、求积、求最大值等操作。
public class Main {
public static void main(String[] args) {
ArrayList<Integer> integers = new ArrayList<>();
integers.add(2);
integers.add(3);
integers.add(3);
Optional<Integer> reduce = integers.stream().reduce((a, b) -> a + b);
System.out.println(reduce.get());
}
}
2.2.4 toArray
toArray
是用于将流中的元素收集到一个数组中。
public class Main {
public static void main(String[] args) {
ArrayList<Integer> integers = new ArrayList<>();
integers.add(2);
integers.add(3);
integers.add(3);
Object[] array = integers.stream().toArray();
System.out.println(array);
}
}
3 流的创建
流操作的对象是集合和数组:
通过集合创建流上面已经提到过了:
List<Integer> l=new ArrayList();
l.stream();
通过数组建立流的方式需要使用到Arrays:
String[] s=new String("111","222","333");
Arrays.stream(s);
4.补充
这里涉及到了大量的数组和集合相互转化的操作,这里做一个补充。
4.1集合转数组
4.1.1集合转数组
Collection接口中定义了两个方法用于将集合中的元素转成数组中的元素,所有实现了Collection接口的集合类型,比如ArrayList,HashSet都必须实现这两个方法,虽然各类集合的具体实现方式可能会不同,但是这两个方法的功能是确定的。
ArrayList<String> list = new ArrayList<>();
String[] strings = (String[]) list.toArray();
4.1.2数组转集合
由于数组是一种特殊的类型,为了更加方便地操作它,JDK提供了一个强大的工具类Arrays,它提供了一个静态方法asList()来实现数组到集合的直接转换。
Arrays.asList()
String[] a = {"a", "b", "c"};
List<String> list = new ArrayList<>(Arrays.asList(a));