最强java8新特性-stream流

简介: Java 8 是一个非常成功的版本,这个版本新增的Stream,配合同版本出现的Lambda ,给我们操作集合(Collection)提供了极大的便利。Stream流是JDK8新增的成员,允许以声明性方式处理数据集合,可以把Stream流看作是遍历数据集合的一个高级迭代器。Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找/筛选/过滤、排序、聚合和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供

Stream流是什么?

Stream(流)是一个来自数据源的元素队列并支持聚合操作

  • 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
  • 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
  • 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。


Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。


Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码


这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。


元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

常用方法举例:

1.1筛选与切片:

中间操作:

  • filter:接收 Lambda ,从流中排除某些元素
  • limit:截断流,使其元素不超过给定数量
  • skip(n):跳过元素,返回一个舍弃了前n个元素的流;若流中元素不足n个,则返回一个空流;与 limit(n) 互补
  • distinct:筛选,通过流所生成的 hashCode() 与 equals() 取除重复元素
List<Employee>emps=Arrays.asList(
newEmployee(101, "Z3", 19, 9999.99),
newEmployee(102, "L4", 20, 7777.77),
newEmployee(103, "W5", 35, 6666.66),
newEmployee(104, "Tom", 44, 1111.11),
newEmployee(105, "Jerry", 60, 4444.44)
);
@Testpublicvoidtest01(){
emps.stream()
        .filter((x) ->x.getAge() >35)
        .limit(3) //短路?达到满足不再内部迭代        .distinct()
        .skip(1)
        .forEach(System.out::println);
}



  • 内部迭代:迭代操作由 Stream API 完成
  • 外部迭代:我们通过迭代器完成




1.2映射:

  • map:接收 Lambda ,将元素转换为其他形式或提取信息;接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
  • flatMap:接收一个函数作为参数,将流中每一个值都换成另一个流,然后把所有流重新连接成一个流

map和flatmap相当于add 和addAll的区别:

add:对("a", "b", "c")以一个集合的形式注入到新数组中 ( "1" ," 2 ", ("a", "b", "c"))

addAll:  把("a", "b", "c")以每个元素直接注入数组中( "1" ," 2 ","a", "b", "c")


map:

@Testpublicvoidtest02(){
List<String>list=Arrays.asList("a", "b", "c");
list.stream()
        .map((str) ->str.toUpperCase())//变为A,B,C        .forEach(System.out::println);
}


flatMap:

publicStream<Character>filterCharacter(Stringstr){
List<Character>list=newArrayList<>();
for (charc : str.toCharArray()) {
list.add(c);
    }
returnlist.stream();
}
@Testpublicvoidtest03(){
List<String>list=Arrays.asList("a", "b", "c");
Test02test02=newTest02();
list.stream()
        .flatMap(test02::filterCharacter)
        .forEach(System.out::println);
}


1.3排序:

  • sorted():自然排序
  • sorted(Comparator c):定制排序


Comparable:自然排序

@Testpublicvoidtest04(){
List<Integer>list=Arrays.asList(1,2,3,4,5);
list.stream()
        .sorted() //comparaTo()        .forEach(System.out::println);
}

Comparator:定制排序

@Testpublicvoidtest05(){
emps.stream()
        .sorted((e1, e2) -> { //compara()if (e1.getAge().equals(e2.getAge())){
returne1.getName().compareTo(e2.getName());
            } else {
returne1.getAge().compareTo(e2.getAge());
            }
        })
        .forEach(System.out::println);
}


1.4查找/匹配:

终止操作:

  • allMatch:检查是否匹配所有元素
  • anyMatch:检查是否至少匹配一个元素
  • noneMatch:检查是否没有匹配所有元素
  • findFirst:返回第一个元素
  • findAny:返回当前流中的任意元素
  • count:返回流中元素的总个数
  • max:返回流中最大值
  • min:返回流中最小值
publicenumStatus {
FREE, BUSY, VOCATION;
}
@Testpublicvoidtest01(){
List<Status>list=Arrays.asList(Status.FREE, Status.BUSY, Status.VOCATION);
booleanflag1=list.stream()
        .allMatch((s) ->s.equals(Status.BUSY));
System.out.println(flag1);
booleanflag2=list.stream()
        .anyMatch((s) ->s.equals(Status.BUSY));
System.out.println(flag2);
booleanflag3=list.stream()
        .noneMatch((s) ->s.equals(Status.BUSY));
System.out.println(flag3);
// 避免空指针异常Optional<Status>op1=list.stream()
        .findFirst();
// 如果Optional为空 找一个替代的对象Statuss1=op1.orElse(Status.BUSY);
System.out.println(s1);
Optional<Status>op2=list.stream()
        .findAny();
System.out.println(op2);
longcount=list.stream()
        .count();
System.out.println(count);
}

1.5 归约 / 收集:

  • 归约:reduce(T identity, BinaryOperator) / reduce(BinaryOperator) 可以将流中的数据反复结合起来,得到一个值
  • 收集:collect 将流转换成其他形式;接收一个 Collector 接口的实现,用于给流中元素做汇总的方法

reduce:

/*** Java:*  - reduce:需提供默认值(初始值)* Kotlin:*  - fold:不需要默认值(初始值)*  - reduce:需提供默认值(初始值)*/@Testpublicvoidtest01(){
List<Integer>list=Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
Integerinteger=list.stream()
        .reduce(0, (x, y) ->x+y);
System.out.println(integer);
}


collect:


List<Employee>emps=Arrays.asList(
newEmployee(101, "Z3", 19, 9999.99),
newEmployee(102, "L4", 20, 7777.77),
newEmployee(103, "W5", 35, 6666.66),
newEmployee(104, "Tom", 44, 1111.11),
newEmployee(105, "Jerry", 60, 4444.44)
);
@Testpublicvoidtest02(){
//放入ListList<String>list=emps.stream()
        .map(Employee::getName)
        .collect(Collectors.toList()); 
list.forEach(System.out::println);
//放入SetSet<String>set=emps.stream()
        .map(Employee::getName)
        .collect(Collectors.toSet());
set.forEach(System.out::println);
//放入LinkedHashSetLinkedHashSet<String>linkedHashSet=emps.stream()
        .map(Employee::getName)
        .collect(Collectors.toCollection(LinkedHashSet::new));
linkedHashSet.forEach(System.out::println);
}
@Testpublicvoidtest03(){
//总数Longcount=emps.stream()
        .collect(Collectors.counting());
System.out.println(count);
//平均值Doubleavg=emps.stream()
        .collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println(avg);
//总和Doublesum=emps.stream()
        .collect(Collectors.summingDouble(Employee::getSalary));
System.out.println(sum);
//最大值Optional<Employee>max=emps.stream()
        .collect(Collectors.maxBy((e1, e2) ->Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println(max.get());
//最小值Optional<Double>min=emps.stream()
        .map(Employee::getSalary)
        .collect(Collectors.minBy(Double::compare));
System.out.println(min.get());
}
@Testpublicvoidtest04(){
//分组Map<Integer, List<Employee>>map=emps.stream()
        .collect(Collectors.groupingBy(Employee::getId));
System.out.println(map);
//多级分组Map<Integer, Map<String, List<Employee>>>mapMap=emps.stream()
        .collect(Collectors.groupingBy(Employee::getId, Collectors.groupingBy((e) -> {
if (e.getAge() >35) {
return"开除";
            } else {
return"继续加班";
            }
        })));
System.out.println(mapMap);
//分区Map<Boolean, List<Employee>>listMap=emps.stream()
        .collect(Collectors.partitioningBy((e) ->e.getSalary() >4321));
System.out.println(listMap);
}
@Testpublicvoidtest05(){
//总结DoubleSummaryStatisticsdss=emps.stream()
        .collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println(dss.getMax());
System.out.println(dss.getMin());
System.out.println(dss.getSum());
System.out.println(dss.getCount());
System.out.println(dss.getAverage());
//连接Stringstr=emps.stream()
        .map(Employee::getName)
        .collect(Collectors.joining("-")); //可传入分隔符System.out.println(str);
}

1.6 案例:

**案例一:**给定一个数字列表,如何返回一个由每个数的平方构成的列表呢?(如:给定【1,2,3, 4,5】,返回【1,4,9,16,25】)

@Testpublicvoidtest01(){
List<Integer>list=Arrays.asList(1, 2, 3, 4, 5);
list.stream()
        .map((x) ->x*x)
        .forEach(System.out::println);
}

**案例二:**怎样使用 map 和 reduce 数一数流中有多少个 Employee 呢?

List<Employee>emps=Arrays.asList(
newEmployee(101, "Z3", 19, 9999.99),
newEmployee(102, "L4", 20, 7777.77),
newEmployee(103, "W5", 35, 6666.66),
newEmployee(104, "Tom", 44, 1111.11),
newEmployee(105, "Jerry", 60, 4444.44)
);
@Testpublicvoidtest02(){
Optional<Integer>result=emps.stream()
        .map((e) ->1)
        .reduce(Integer::sum);
System.out.println(result.get());

1.7:并行流:

  • 并行流:就是把一个内容分成几个数据块,并用不同的线程分别处理每个数据块的流
  • Java 8 中将并行进行了优化,我们可以很容易的对数据进行操作;Stream API 可以声明性地通过 parallel() 与 sequential() 在并行流与串行流之间切换

Java 8 并行流 / 串行流:

@Testpublicvoidtest03(){
//串行流(单线程):切换为并行流 parallel()//并行流:切换为串行流 sequential()LongStream.rangeClosed(0, 100000000L)
        .parallel() //底层:ForkJoin        .reduce(0, Long::sum);
}
相关文章
|
20天前
|
Java Unix Go
【Java】(8)Stream流、文件File相关操作,IO的含义与运用
Java 为 I/O 提供了强大的而灵活的支持,使其更广泛地应用到文件传输和网络编程中。!但本节讲述最基本的和流与 I/O 相关的功能。我们将通过一个个例子来学习这些功能。
117 1
|
1月前
|
Java API 数据处理
Java新特性:使用Stream API重构你的数据处理
Java新特性:使用Stream API重构你的数据处理
|
1月前
|
Java 大数据 API
Java Stream API:现代集合处理与函数式编程
Java Stream API:现代集合处理与函数式编程
196 100
|
1月前
|
Java API 数据处理
Java Stream API:现代集合处理新方式
Java Stream API:现代集合处理新方式
217 101
|
1月前
|
并行计算 Java 大数据
Java Stream API:现代数据处理之道
Java Stream API:现代数据处理之道
189 101
Java API 开发者
57 0
|
1月前
|
存储 数据可视化 Java
Java Stream API 的强大功能
Java Stream API 是 Java 8 引入的重要特性,它改变了集合数据的处理方式。通过声明式语法,开发者可以更简洁地进行过滤、映射、聚合等操作。Stream API 支持惰性求值和并行处理,提升了代码效率和可读性,是现代 Java 开发不可或缺的工具。
Java Stream API 的强大功能
|
2月前
|
存储 NoSQL Java
Java Stream API:集合操作与并行处理
Stream API 是 Java 8 提供的集合处理工具,通过声明式编程简化数据操作。它支持链式调用、延迟执行和并行处理,能够高效实现过滤、转换、聚合等操作,提升代码可读性和性能。
|
2月前
|
存储 Java API
Java Stream API:现代数据处理之道
Java Stream API:现代数据处理之道
338 188
|
2月前
|
存储 Java API
Java Stream API:现代数据处理之道
Java Stream API:现代数据处理之道
244 92