Stream 流
1. Stream的定义
来自数据源的支持聚合操作的元素序列。
即一个流对外提供接口,接收特定的数据。
数据源:数据结构,数组,文件等。
聚合操作:如filter,map,reduce。find,sorted等。
许多流的操作返回也是一个流,且进行流操作时候,用户感知不到循环遍历。
2. 流的工作流程
- 流的创建。
- 流的转换,将流转换为其他流的中间操作。
- 流的计算结果。这个步骤之后,流就不能用了。
流的创建
1. Collection接口的stream方法。
Stream<String> as = new ArrayList<>().stream();
Stream<String> hs = new HashSet<>().stream();
- 还有其他子类,如LinkList, LinkSet, TreeSet等。
2. Arrays.stream可以将数组转化为Stream。
Stream<String> b1 = Arrays.stream("a,b,c,d,e", split(","));
3. 利用Stream 类进行转化。
- of方法,直接将数组转化。
Stream<Integer> c1 = Stream.of(new Integer[5]);
Stream<String> c2 = Stream.of("a,c,b".split(","));
Stream<String> c3 = Stream.of("a", "b", "c");
- empty方法,产生一个空流。
Stream<String> d1 = Stream.empty();
- generate方法,接收一Lambda表达式。
Stream<String> e1 = Stream.generate(() -> "hello");
Stream<Double> e2 = Stream.genarate(Math::random);
- iterate方法,接收一个种子,和一个Lambda表达式。
Stream<BigInteger> f1 = Stream.iterate(BigInteger.ZERO, n -> n.add(BigInteger.ONE));
4. 基本类型流(只有三种)
- IntStream, LongStream, DoubleStream。
IntStream s1 = IntStream.of(1,2,3,5);
s1.IntStream.generate(() -> (int)(Math.random()*100));
s1.IntStream.range(1, 5);
s1.Arrays.stream(new int[] {1,2,4});
//将基本类型与包装类的转化。
IntStream s2 = IntStream.of(1,2,4,5);
//基本类转为包装类。
Stream<Integer> s3 = s2.boxed();
//包装类转为基本类。
IntStream s4 = s3.mapToInt(Integer::intValue);
5. 并行流
使得所有中间转化都以并行方式进行。
- Collections.parallelStream():将集合元素转为一个并行流。
- Stream.parallel()方法,产生一个并行流。
IntStream s1 = IntStream.range(1, 100000);
Long e1 = s1.parallel().filter(n -> n%2 == 0).count();
System.out.println(e1);
谨慎使用并行流。
- 其他类/方法产生Stream流。
- Files.lines方法
Stream<String> contenrs = Files.lines(Paths.get("文件路径"));
- Pattern的splitAsStream方法。
Stream<String> words = Pattern.compile(",")splitAsStream("a,b,c");
流的转化
- 从一种流到另一种流。
- 过滤 filter。
– filter(Prelicate<? super T> predicate),接收一个Lambda表达式,对每一个元素进行判定符合要求的留下。
Stream<Integer> s1 = Stream.of(1,2,3,4,5);
Stream<Integer> s2 = s1.filter(n -> n>2);
s2.forEach(System.out::println);
- 去重 distinct。
– 删除元素中重复的部分。
Stream<Integer> s1 = Stream.of(1,1,2,2,33);
Stream<Integer> s2 = s1.distinct();
s2.forEach(System.out::println);
//1,2,33;
- 对于对象的判定,先调用hashCode方法,再调用equals方法。
ArrayList<Student> students = new ArrayList<>();
students.add(new Student("Tom", 20));
students.add(new Student("Tom", 20));
students.add(new Student("Peter", 20));
students.add(new Student("Bob", 13));
//先调用对象的hashCode方法,再调用其equals方法进行重判。
Stream<Student> s3 = students.stream().distinct();
s3.forEach(System.out.println);
- 排序 sorted。
– sorted()。
– 提供Comparator,对流进行排序。
Stream<String> s3 = Stream.of(ppp).sorted(
Comparator.comparing(String::length));
– 对流的自定义对象元素进行排序时,调用对象的compareTo方法。
Stream<Cat> s4 = cats.stream().sorted();
//调用Cat类中自定义的compareTo方法。
- 转化 map。
– 利用方法引用对流中的每一元素进行函数计算。
Stream<Double> s1 = Stream.of(-1.1,-2,3.3);
Stream<Double> s2 = s1.map(Math::abs);
s2.forEach(System.out::println);
//1.1,2,3.3。
– 利用Lambda表达式对流的每一个元素进行函数计算。
Stream<Integer> s3 = Stream.of(-1,-2,3);
Stream<Integer> s4 = s3.map(n -> n*n);
s4.forEach(System.out::println);
//1,4,9。
– 利用方法引用,对流每一个元素进行计算并返回stream。
String[] planets = new String[]{"Mercury", "Verus", "Earth"};
Stream<Stream<String>> s5 = Stream.of(planets).map(word -> letter(word));
s5.forEach(System.out::println);
public static Stream<String> letter(String word){
ArrayList<String> list = new ArrayList<>();
for(int i = 0; i < word.length(); i++){
list.add(word.substring(i, i+1));
}
return list.stream();
}
– 利用方法引用,对流每一个元素进行计算返回stream,并合并。
只需要将上述代码中的map方法换为flatmap方法即可。
- 转化
– 抽取 limit。
– 跳过skip。
IntStream s1 = IntStream.range(0, 10);
IntStream s2 = S1.limit(8);//0-8
IntStream s3 = s2.skip(3);//3-8
– 连接 concat。
Stream s4 = Stream.concat(letter(“hello”, letter(“world”)));
//‘h’e’l’l’o’w’o’r’l’d’
- 其他
– 额外调试 peek。
Stream s1 = Stream.iterate(1.0, n -> n*2).peek(n -> System.out.println(n)).limit(5);
Optianal
Optional
-
一个包装器对象,要么包装了类型T的对象,要么没有包装任何对象。
– T有值,直接返回T对象,T是null,可以返回一个代替值。 -
Optional创建
– of方法。
– empty方法。
– ofNullable方法,对象可能为null。安全创建。
Optional<String> s1 = Optional.of(new String("abd"));
Optional<String> s2 = Optional.empty();
String s3 = null;
Optional<String> s4 = Optional.ofNullable(s3);
//s3不为null,s4为s3,否则s4为Optional.empty().
- Optional使用
– get方法,获取值,不安全。
– orElse方法,获取值,如果为null,采用代替值。
– orElseGet方法,获取值,如果为null,采用Lambda表达式值返回。
– orElseThrow方法,获取值,如果为null,则抛出异常。
– ifPresent方法,判断是否为空,不为空返回true。
– isPresent(Consumer),判断是否为空,不为空,进行后续Consumer操作。为空,不进行操作。
– map(Function),将值传递给Function函数计算。为空则不计算。
流的计算
- 简单约简(聚合函数)
– count(),计数。
– max(Comparator),最大值,需要比较器。
– min(Comparator), 最小值,需要比较器。
– findFirst(),找到第一个元素。
– findAny(),找到任意一个元素。
– anyMatch(Predicate),有一个元素满足Predicate,则返回true。
– allMatch(Predicate),所有元素满足Predicate,则返回true。
– noneMatch(Predicate),没有元素满足Predicate,则返回true。 - 自定义约简
– reduce,传递一个二元函数BinaryOperator,对流进行操作。
Integer[] a = new Integer[] {1, 2, 3, 4, 5};
Stream<Integer> s1 = Stream.of(a);
Optional<Integer> sum = s1.reduce(Math::sum);
sum.get().forEach(System.out::println);
Stream<Integer> s2 = Stream.of(a);
Optional<Integer> product = s2.reduce((x, y) -> x*y);
System.out.println(product.get());
- 查看,遍历元素。
– iterator(),遍历元素。
– forEach(Cunsumer),应用一个方法到每一个元素上。
Integer[] a = new Integer[]{1,2,3,4,5};
Stream<Integer> s1 = Stream.of(a);
Iterator<Integer> it = s1.filter(n -> n>2).iterator();
while(it.hasNext()){
System.out.println(it.next());
}
Stream<Integer> s2 = Stream.of(a);
s2.filter(n -> n<4).forEach(System.out.println);
- 放到数据结构中。
– toArray(),结果转为数组中。
– collect(Collectors.toList()),结果转为List。
– collect(Collectors.toSet()),结果转为Set。
– collect(Collectors.toMap()),结果转为Map。
– collect(Collectors.joinning()),结果连接起来。
Integer[] a = new Integer[] {2,4,6,8};
//将流存储为List
Stream<Integer> s1 = Stream.of(a);
List<Integer> list1 = s1.collect(Collectors.toList());
//将流存储为指定的LinkedList
Stream<Integer> s2 = Stream.of(a);
List<Integer> list2 = s2.collect(Collectors.toCollection(LinkedList::new));
//将流存储为Set
Stream<Integer> s3 = Stream.of(a);
Set<Integer> set1 = s3.collect(Collectors.toSet());
//将流变换为字符流,并连接起来
Stream<Integer> s4 = Stream.of(a);
String result = s4.map(String::valueOf).collect(Collectors.joining());
System.out.println(result); //2468
//将流变换为字符流,并连接起来
Stream<Integer> s5 = Stream.of(a);
String result2 = s5.map(String::valueOf).collect(Collectors.joining(","));
System.out.println(result2); //2,4,6,8
List<Person> persons = new ArrayList<Person>();
persons.add(new Person(1, "Jerry"));
persons.add(new Person(2, "Tom"));
//将流存储为Map
Stream<Person> s6 = persons.stream();
Map<Integer, String> map1 = s6.collect(Collectors.toMap(Person::getId, Person::getName));
- 流的高阶计算,分组groupingBy和分区partitionBy。
- 以上方法均在java.util.stream.Collectors中。