JDK8新特性之Stream流

简介: JDK8新特性之Stream流-Stream流常用的API以及案例实操

1.原始集合处理数据的弊端->Stream流优势之处,案例演示

  1. 自定义一个集合,集合中给定一些名字
  2. 获取所有姓李的信息
  3. 获取名字长度为2的人员
  4. 输出所有用户的信息
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class StreamDemo01 {
   

    public static void main(String[] args) {
   

        //1. 自定义一个集合,集合中给定一些名字
        List<String> list = Arrays.asList("李一一","李一","李二二","李二");
        //2. 获取所有姓李的信息
        ArrayList<String> list1 = new ArrayList<>();
        for(String str:list){
   
            if(str.startsWith("李")) list1.add(str);
            else continue;
        }
        //3. 获取名字长度为2的人员
        List<String> list2 = new ArrayList<>();
        for (String s : list1) {
   
            if(s.length() == 2) list2.add(s);
            else continue;
        }
        //4. 输出所有用户的信息
        for (String s : list2) {
   
            System.out.println(s);
        }
    }
}

上面的代码针对与我们不同的需求总是一次次的循环收集记过.这时我们希望有更加高效的处理方式,这时我们就可以通过JDK8中提供的Stream API来解决这个问题了。

演进为Stream的解决方案:

import java.util.Arrays;
import java.util.List;

public class StreamDemo02 {
   

    public static void main(String[] args) {
   
        //1. 自定义一个集合,集合中给定一些名字
        List<String> list = Arrays.asList("李一一","李一","李二二","李二");
        //2. 获取所有姓李的信息、过滤、输出
        list.stream()
                .filter(str->str.startsWith("李"))
                .filter(str-> str.length()==2)
                .forEach(s-> {
   System.out.println(s);});
    }
}

2. Steam流式思想概述

易错点

注意:Stream和IO流没有任何关系!

基本思想

Stream流式思想类似于工厂车间的“生产流水线”,Stream流不是一种数据结构,不保存数据,而是对数据进行加工处理。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。

作用

Stream API能让我们快速完成许多复杂的操作,如筛选、切片、映射、查找、去除重复,统计,匹配和归约。

3. Stream流的获取方式

3.1 根据Collection获取

​ 首先,java.util.Collection 接口中加入了default方法 stream,也就是说Collection接口下的所有的实现都可以通过steam方法来获取Stream流。

public static void main(String[] args) {
   
    List<String> list = new ArrayList<>();
    list.stream();
    Set<String> set = new HashSet<>();
    set.stream();
    Vector vector = new Vector();
    vector.stream();
}

​ Map接口没有实现Collection接口,这时我们可以根据Map获取对应的key value的集合。

public static void main(String[] args) {
   
    Map<String,Object> map = new HashMap<>();
    Stream<String> stream = map.keySet().stream(); // key
    Stream<Object> stream1 = map.values().stream(); // value
    Stream<Map.Entry<String, Object>> stream2 = map.entrySet().stream(); // entry
}

3.2 通过Stream的of方法

注意:基本数据类型的数组是不行的
在实际开发中我们不可避免的是会操作到数组中的数据,由于数组对象不可能添加默认方法,所有Stream接口中提供了静态方法of

public class StreamDemo{
   

    public static void main(String[] args) {
   
        Stream<String> stream1 = Stream.of("q", "w", "e");
        stream1.forEach(System.out::println);
        String[] arr1 = {
   "aa","bb","cc"};
        Stream<String> stream2 = Stream.of(arr1);
        stream2.forEach(System.out::println);
        Integer[] arr2 = {
   1,2,3,4};
        Stream<Integer> stream3 = Stream.of(arr2);
        stream3.forEach(System.out::println);
    }
}

4.Stream常用方法介绍

Stream流模型的常用方法很多,这里介绍一些常用的API。这些方法可以被分成两种:

方法名 方法作用 返回值类型 方法种类
count 统计个数 long 终结
forEach 逐一处理 void 终结
filter 过滤 Stream 函数拼接
limit 取用前几个 Stream 函数拼接
skip 跳过前几个 Stream 函数拼接
map 映射 Stream 函数拼接
concat 组合 Stream 函数拼接

终结方法:返回值类型不再是 Stream 类型的方法,不再支持链式调用。本小节中,终结方法包括 count 和 forEach 方法。

非终结方法:返回值类型仍然是 Stream 类型的方法,支持链式调用。(除了终结方法外,其余方法均为非终结方法。)

Stream注意事项(重要)

  1. Stream只能操作一次

  2. Stream方法返回的是新的流

  3. Stream不调用终结方法,中间的操作不会执行

4.1 forEach

Stream流中forEach用来遍历流中的数据,该方法接受一个Consumer接口,会将每一个流元素交给函数处理

    public static void main(String[] args) {
   
        Stream.of("硕", "风", "和").forEach(System.out::println);;
    }

4.2 count

Stream流中的count方法用来统计其中的元素个数的该方法返回一个long值,代表元素的个数。

public class StreamDemo {
   

    public static void main(String[] args) {
   
        long count = Stream.of(1, 2, 3,4,5).count();
        System.out.println(count);
    }
}

4.3 filter

filter方法的作用是用来过滤数据的。返回符合条件的数据,可以通过filter方法将一个流转换成另一个子集流,该接口接收一个Predicate函数式接口参数作为筛选条件

public class StreamDemo {
   

    public static void main(String[] args) {
   
         Stream.of(1, 2, 3,4,5,6)
                 .filter((s)->s>=3)
                 .forEach(System.out::println);

    }
}

4.4 limit

limit方法可以对流进行截取处理,支取前n个数据,参数是一个long类型的数值,如果集合当前长度大于参数就进行截取,否则不操作:

public class StreamDemo{
   

    public static void main(String[] args) {
   
        Stream.of(1, 2, 3,4,5,6)
                 .limit(3)
                 .forEach(System.out::println);

    }
}

4.5 skip

如果希望跳过前面几个元素,可以使用skip方法获取一个截取之后的新流,案例如下所示:

public class StreamDemo{
   

    public static void main(String[] args) {
   
        Stream.of(1, 2, 3,4,5,6)
                 .skip(3)
                 .forEach(System.out::println);

    }
}

4.6 map类型转换

如果我们需要将流中的元素映射到另一个流中,可以使用map方法:
该接口需要一个Function函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的数据

public class StreamDemo{
   

    public static void main(String[] args) {
   
        Stream.of(1, 2, 3,4,5,6)
                 .map(num->num.toString())
                 .forEach(System.out::println);

    }
}

4.7 sorted

如果需要将数据排序,可以使用sorted方法:
在使用的时候可以根据自然规则排序,也可以通过比较强来指定对应的排序规则

public class StreamDemo{
   

    public static void main(String[] args) {
   
         Stream.of("9", "6", "5","3","2","1","0")
                 .map(msg->Integer.parseInt(msg))
                 .sorted((o1,o2)->o1-o2)
                 .forEach(System.out::println);
    }
}

4.8 distinct

如果要去掉重复数据,可以使用distinct方法,案例如下:

public class StreamDemo {
   

    public static void main(String[] args) {
   
        Stream.of("9", "6","8", "5","3","2","2","1","0")
                 .map(Integer::parseInt)
                 .sorted((o1,o2)->o1-o2) 
                 .distinct() // 去掉重复的记录
                 .forEach(System.out::println);
    }
}

注意注意:Stream流中的distinct方法对于基本数据类型是可以直接出重的,但是对于自定义类型,我们是需要重写hashCode和equals方法来移除重复元素。

4.9 match

match是一个终结的方法
如果需要判断数据是否匹配指定的条件,可以使用match相关的方法
相关API如下

boolean anyMatch(Predicate<? super T> predicate); // 元素是否有任意一个满足条件
boolean allMatch(Predicate<? super T> predicate); // 元素是否都满足条件
boolean noneMatch(Predicate<? super T> predicate); // 元素是否都不满足条件

案例演示:

public class StreamDemo{
   

    public static void main(String[] args) {
   
        // 判断元素是否都大于3
        boolean b1 = Stream.of("9", "6", "8", "5", "3", "2", "2", "1", "0")
                .map(Integer::parseInt)
                .allMatch(s -> s > 3);
        System.out.println(b1);
        // 判断元素是否存在大于3的元素
        boolean b2 = Stream.of("9", "6", "8", "5", "3", "2", "2", "1", "0")
                .map(Integer::parseInt)
                .anyMatch(s -> s > 3);
        System.out.println(b2);
        // 判断元素是否都不大于3
        boolean b3 = Stream.of("9", "6", "8", "5", "3", "2", "2", "1", "0")
                .map(Integer::parseInt)
                .noneMatch(s -> s > 3);
        System.out.println(b3);
    }
}

4.10 find

如果我们需要找到某些数据,可以使用find方法来实现,如下面所示,案例如下:

public class StreamDemo{
   

    public static void main(String[] args) {
   

        Optional<String> first = Stream.of("1", "5", "1").findFirst();
        System.out.println(first.get());

        Optional<String> any = Stream.of("1", "1", "7").findAny();
        System.out.println(any.get());
    }
}

4.11 max和min

如果我们想要获取最大值和最小值,那么可以使用max和min方法,案例如下:

public class StreamDemo{
   

    public static void main(String[] args) {
   

        Optional<Integer> min = Stream.of("9", "6","8", "5","3","2","2","1","0")
                .map(Integer::parseInt)
                .min((o1,o2)->o2-o1);// 取来排序后第一个元素的位置为元素的最小值
        System.out.println(min.get());

        Optional<Integer> max = Stream.of("9", "6","8", "5","3","2","2","1","0")
                .map(Integer::parseInt)
                .max((o1,o2)->o2-o1);// 取来排序后最后一个元素的位置为元素的最大值
        System.out.println(max.get());
    }
}

4.12 reduce方法

如果需要将所有数据归纳得到一个数据,可以使用reduce方法,案例如下:

public class StreamDemo {
   

    public static void main(String[] args) {
   
        Integer sum = Stream.of("9", "6","8", "5","3","2","2","1","0")
                .map(Integer::parseInt)
                // 第一次的时候会将默认值赋值给x,以后每次将上一次的操作结果赋值给x y就是每次从数据中获取的元素
                .reduce(0, (x, y) -> {
   
                    //System.out.println("x:"+x+",y:"+y);
                    return x + y;
                });
        System.out.println(sum);
    }
}

4.13 map和reduce的组合

在实际开发中我们经常会将map和reduce一块来使用

public class StreamDemo {
   

    public static void main(String[] args) {
   
        // 1.求出所有年龄的总和
        Integer sumAge = Stream.of(
                new Person("a", 18)
                , new Person("b", 22)
        ).map(Person::getAge) // 实现数据类型的转换
                .reduce(0, Integer::sum);
        System.out.println(sumAge);

        // 2.求出所有年龄中的最大值
        Integer maxAge = Stream.of(
                new Person("a", 18)
                , new Person("b", 22)
        ).map(Person::getAge) // 实现数据类型的转换,符合reduce对数据的要求
                .reduce(0, Math::max); // reduce实现数据的处理
        System.out.println(maxAge);
        // 3.统计 字符 a 出现的次数
        Integer count = Stream.of("a", "b", "c", "d", "a", "c", "a")
                .map(ch -> "a".equals(ch) ? 1 : 0)
                .reduce(0, Integer::sum);
        System.out.println(count);
    }
}

4.14 mapToInt

如果需要将Stream中的Integer类型转换成int类型,可以使用mapToInt方法来实现,案例如下

public class StreamDemo{
   

    public static void main(String[] args) {
   
        // Integer占用的内存比int多很多,在Stream流操作中会自动装修和拆箱操作
        Integer arr[] = {
   7,4,3,6,7,3,4};
        // 为了提高程序代码的效率,我们可以先将流中Integer数据转换为int数据,然后再操作
        IntStream intStream = Stream.of(arr)
                .mapToInt(Integer::intValue);
        intStream.filter(i->i>3)
                .forEach(System.out::println);

    }
}

4.15 concat

如果有两个流,希望合并成为一个流,那么可以使用Stream接口的静态方法concat,案例如下:

public class StreamDemo{
   

    public static void main(String[] args) {
   
        Stream<String> stream1 = Stream.of("1","2","3");
        Stream<String> stream2 = Stream.of("3", "2", "1");
        Stream.concat(stream1,stream2).forEach(System.out::println);
    }
}

5. 总结

现在面试考察的范围越来越广,这就需要在平常的学习生活中不断的积累,等待厚积薄发的时候。

相关文章
|
2月前
|
安全 JavaScript 前端开发
JDK1.8的重要的新特性与功能
Java Development Kit (JDK) 1.8,也称为Java 8,是Java平台的一个重大更新,于2014年3月发布。它引入了多项新特性、新的API和性能提升
73 3
|
3月前
|
监控 安全 Java
探索Java的未来:JDK 18新特性全览
探索Java的未来:JDK 18新特性全览
80 0
|
3月前
|
缓存 安全 Java
JDK 14全景透视:每个Java开发者必知的新特性
JDK 14全景透视:每个Java开发者必知的新特性
54 0
|
3月前
|
JavaScript 前端开发 安全
Java新纪元:一探JDK 15的全新特性
Java新纪元:一探JDK 15的全新特性
46 0
|
3月前
|
JSON Java API
探秘JDK 13的黑科技:新特性一览
探秘JDK 13的黑科技:新特性一览
51 0
|
3月前
|
Java 测试技术 API
深度剖析JDK 11全新特性:编程艺术的巅峰之作
深度剖析JDK 11全新特性:编程艺术的巅峰之作
47 0
|
3月前
|
存储 Java 数据管理
探秘JDK 10:崭新特性悉数解析
探秘JDK 10:崭新特性悉数解析
31 0
|
3月前
|
JSON 编解码 Java
Java升级:JDK 9新特性全面解析“
Java升级:JDK 9新特性全面解析“
46 0
|
4天前
|
算法 Java 编译器
升级指南之JDK 11+ 新特性和AJDK
本文详细介绍了JDK个版本之间的特性、区别以及JDK版本更迭时优化了哪些地方,对JDK的版本选择给出了建议,以及升级教程。
|
11天前
|
存储 安全 Java
JDK22发布了!来看看有哪些新特性
以上是介绍 JDK22新特性的全部内容了,突然V哥想要感慨一下,技术之路,学无止境,选择 IT 技术,作个纯粹的人,享受研究技术的过程,这种带来的快感,也许只有真正热爱编程的人才能有体会。