最强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);
}
相关文章
|
3月前
|
存储 安全 Java
Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
【10月更文挑战第17天】Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
96 2
|
3月前
|
存储 Java
深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。
【10月更文挑战第16天】本文深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。HashSet基于哈希表实现,添加元素时根据哈希值分布,遍历时顺序不可预测;而TreeSet利用红黑树结构,按自然顺序或自定义顺序存储元素,确保遍历时有序输出。文章还提供了示例代码,帮助读者更好地理解这两种集合类型的使用场景和内部机制。
56 3
|
3月前
|
存储 Java 数据处理
Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位
【10月更文挑战第16天】Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位。本文通过快速去重和高效查找两个案例,展示了Set如何简化数据处理流程,提升代码效率。使用HashSet可轻松实现数据去重,而contains方法则提供了快速查找的功能,彰显了Set在处理大量数据时的优势。
47 2
|
1月前
|
存储 Java 开发者
什么是java的Compact Strings特性,什么情况下使用
Java 9引入了紧凑字符串特性,优化了字符串的内存使用。它通过将字符串从UTF-16字符数组改为字节数组存储,根据内容选择更节省内存的编码方式,通常能节省10%至15%的内存。
|
1月前
|
存储 Java 数据挖掘
Java 8 新特性之 Stream API:函数式编程风格的数据处理范式
Java 8 引入的 Stream API 提供了一种新的数据处理方式,支持函数式编程风格,能够高效、简洁地处理集合数据,实现过滤、映射、聚合等操作。
80 6
|
1月前
|
Java API 开发者
Java中的Lambda表达式与Stream API的协同作用
在本文中,我们将探讨Java 8引入的Lambda表达式和Stream API如何改变我们处理集合和数组的方式。Lambda表达式提供了一种简洁的方法来表达代码块,而Stream API则允许我们对数据流进行高级操作,如过滤、映射和归约。通过结合使用这两种技术,我们可以以声明式的方式编写更简洁、更易于理解和维护的代码。本文将介绍Lambda表达式和Stream API的基本概念,并通过示例展示它们在实际项目中的应用。
|
1月前
|
Rust 安全 Java
Java Stream 使用指南
本文介绍了Java中Stream流的使用方法,包括如何创建Stream流、中间操作(如map、filter、sorted等)和终结操作(如collect、forEach等)。此外,还讲解了并行流的概念及其可能带来的线程安全问题,并给出了示例代码。
|
2月前
|
分布式计算 Java API
Java 8引入了流处理和函数式编程两大新特性
Java 8引入了流处理和函数式编程两大新特性。流处理提供了一种声明式的数据处理方式,使代码更简洁易读;函数式编程通过Lambda表达式和函数式接口,简化了代码书写,提高了灵活性。此外,Java 8还引入了Optional类、新的日期时间API等,进一步增强了编程能力。这些新特性使开发者能够编写更高效、更清晰的代码。
43 4
|
2月前
|
安全 Java API
Java中的Lambda表达式与Stream API的高效结合####
探索Java编程中Lambda表达式与Stream API如何携手并进,提升数据处理效率,实现代码简洁性与功能性的双重飞跃。 ####
35 0
|
2月前
|
Java API 数据处理
探索Java中的Lambda表达式与Stream API
【10月更文挑战第22天】 在Java编程中,Lambda表达式和Stream API是两个强大的功能,它们极大地简化了代码的编写和提高了开发效率。本文将深入探讨这两个概念的基本用法、优势以及在实际项目中的应用案例,帮助读者更好地理解和运用这些现代Java特性。