Java基础学习(十二)

Java基础学习(十二):Stream流

本文为个人学习记录,内容学习自 黑马程序员


概念

  • 作用:结合 Lambda 表达式,简化数组、集合的操作
  • 使用步骤:①先得到一条 Stream 流,并把数据放上去 ②利用 Stream 流中的 API 进行各种操作,例如过滤、转换、统计、打印等等

获取 Stream 流

获取方式 方法名 说明
单列集合 default Stream<E> stream() Collection 中的默认方法
双列集合 无法直接使用 Stream 流
数组 public static <T> Stream<T> stream(T[] array) Arrays 工具类中的静态方法
同类型零散数据 public static <T> Stream<T> of(T... values) Stream 接口中的静态方法
  1. 单列集合

    ArrayList<String> list = new ArrayList<>();
    Collections.addAll(list, "a", "b", "c", "d", "e");
    Stream<String> stream = list.stream();
    
  2. 双列集合

    HashMap<String, Integer> hm = new HashMap<>();
    hm.put("a", 1);
    hm.put("b", 2);
    hm.put("c", 3);
    // 双列集合无法直接使用Stream流,需要先转换成单列集合
    Set<Map.Entry<String, Integer>> entries = hm.entrySet();
    Stream<Map.Entry<String, Integer>> stream = entries.stream();
    
  3. 数组

    String[] arr = {"a", "b", "c", "d", "e"};
    Stream<String> stream = Arrays.stream(arr);
    
  4. 同类型零散数据

    Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
    

    注意:该方法的形参是可变参数,可以传递零散数据,也可以传递数组;当传递数组时,如果是引用数据类型的数组不会有问题,但如果是基本数据类型的数组时会将整个数组当作一个元素放到 Stream 流中

    int[] arr1 = {1, 2, 3};
    Integer[] arr2 = {1, 2, 3};
    Stream.of(arr1).forEach(s -> System.out.print(s + " "));			// 输出为 [I@404b9385 
    Stream.of(arr2).forEach(s -> System.out.print(s + " "));			// 输出为 1 2 3 
    

Stream 流的中间方法

方法名 说明
Stream<T> filter(Predicate<? super T> predicate) 过滤
Stream<T> limit(long maxSize) 获取前几个元素
Stream<T> skip(long n) 跳过前几个元素
Stream<T> distinct() 元素去重,底层采用HashSet,依赖 hashCode 和 equals 方法
static <T> Stream<T> concat(Stream a, Stream b) 合并 a 和 b 两个流为一个流
Stream<R> map(Function<T, R> mapper) 转换流中的数据类型
  1. filter 方法

    ArrayList<String> list = new ArrayList<>();
    Collections.addAll(list, "a", "b", "c", "ac", "ab");
    list.stream().filter(new Predicate<String>() {
        @Override
        // s表示流中的每一个元素
        // 返回值为true,表示当前数据留下
        // 返回值为false,表示当前数据舍弃
        public boolean test(String s) {
            return s.startsWith("a");
        }
    }).forEach(s -> System.out.print(s + " "));								// 输出为 "a ac ab "
    
  2. limit 方法

    ArrayList<String> list = new ArrayList<>();
    Collections.addAll(list, "a", "b", "c", "ac", "ab");
    list.stream().limit(3).forEach(s -> System.out.print(s + " "));			// 输出为 "a b c "
    
  3. skip 方法

    ArrayList<String> list = new ArrayList<>();
    Collections.addAll(list, "a", "b", "c", "ac", "ab");
    list.stream().skip(3).forEach(s -> System.out.print(s + " "));			// 输出为 "ac ab "
    
  4. distinct 方法

    ArrayList<String> list = new ArrayList<>();
    Collections.addAll(list, "a", "b", "c", "ac", "ab", "a");
    list.stream().distinct().forEach(s -> System.out.print(s + " "));		// 输出为 "a b c ac ab"
    
  5. concat 方法

    ArrayList<String> list = new ArrayList<>();
    Collections.addAll(list, "a", "b");
    Stream.concat(list.stream(), list.stream()).forEach(s -> System.out.print(s + " "));  // 输出为 "a b a b "
    

    注意:尽量保证要合并的流数据类型一致,如果二者不一致那么得到的流是二者共同的父类

  6. map 方法

    ArrayList<String> list = new ArrayList<>();
    Collections.addAll(list, "a-1", "b-2", "c-3", "ac-4", "ab-5");
    // Function 为函数式接口,第一个类型为流中原本的数据类型,第二个类型为转换后的类型
    list.stream().map(new Function<String, Integer>() {
        @Override
        // s依次表示流中的每一个数据
        // 返回值表示转换后的数据,类型为转换后的类型
        public Integer apply(String s) {
            String[] arr = s.split("-");
            String s1 = arr[1];
            int i = Integer.parseInt(s1);
            return i;
        }
    }).forEach(s -> System.out.print(s + " "));								// 输出为 "1 2 3 4 5 "
    
  7. 注意事项

    • 使用中间方法后,原来的流就不存在了,因此没有必要保存过程中产生的流,建议直接采用链式编程
    • 修改 Stream 流中的数据,不会影响原来集合或者数组中的数据

Stream 流的终结方法

方法名 说明
void forEach(Consumer action) 遍历
long count() 统计
toArray() 收集流中的数据,放到数组中
collect(Collector collector) 收集流中的数据,放到集合中
  1. forEach 方法

    // 完整格式
    Stream<String> stream = list.stream();
    stream.forEach(new Consumer<String>() {
        @Override
        public void accept(String s) {
            System.out.println(s);
        }
    });
    
    // 简化格式
    list.stream().forEach(s -> System.out.println(s));
    
  2. count 方法

    ArrayList<String> list = new ArrayList<>();
    Collections.addAll(list, "a", "b", "c", "ac", "ab");
    long count = list.stream().count();
    System.out.println(count);													// 输出为 5
    
  3. toArray 方法

    ArrayList<String> list = new ArrayList<>();
    Collections.addAll(list, "a", "b", "c", "ac", "ab");
    // 采用空参构造:生成 Object 类型的数组
    Object[] arr = list.stream().toArray();
    // 采用有参构造:根据需要定义数组类型
    // 形参中的IntFunction为函数式接口,需要采用匿名内部类或者Lambda表达式
    // IntFunction接口的泛型:具体的数组类型,此处为String[]
    // apply方法的形参:流中数据的个数
    // apply方法的返回值:具体类型的数组,此处创建了一个String数组,长度和流中数据的个数一致
    String[] arr2 = list.stream().toArray(new IntFunction<String[]>() {
        @Override
        public String[] apply(int value) {
            return new String[value];
        }
    });
    
  4. collect 方法

    ArrayList<String> list = new ArrayList<>();
    Collections.addAll(list, "a-1", "b-2", "c-3", "ac-4", "ab-5");
    // 通过Collectors.toList()方法创建新的List集合
    List<String> newList = list.stream().collect(Collectors.toList());
    // 通过Collectors.toSet()方法创建新的Set集合
    Set<String> newSet = list.stream().collect(Collectors.toSet());
    // 通过Collectors.toMap()方法创建新的Map集合
    // 不同点在于,将Stream流中的数据收集到Map中时,需要指定键和值的获取规则
    // toMap()方法的第一个形参指定了键的获取规则,第二个形参指定了值的获取规则
    // toMap()方法的第一个形参:泛型一表示流中数据的类型,泛型二表示键的数据类型,apply方法的形参为流中的数据,返回值为生成的键
    // toMap()方法的第二个形参:泛型一表示流中数据的类型,泛型二表示值的数据类型,apply方法的形参为流中的数据,返回值为生成的值
    Map<String, Integer> map = list.stream().collect(Collectors.toMap(new Function<String, String>() {
                      @Override
                      public String apply(String s) {
                          return s.split("-")[0];
                      }
                  },
                    new Function<String, Integer>() {
                        @Override
                        public Integer apply(String s) {
                            return Integer.parseInt(s.split("-")[1]);
                        }
                    }));
            System.out.println(map);									// 输出为 {ab=5, a=1, ac=4, b=2, c=3}
    
  5. 注意事项:

    • 使用终结方法后,原来的流就不存在了,此时无法再调用其他方法
    • 使用 collect 方法收集到 Map 集合中时,键不能重复,否则会报错
posted @   victoria6013  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示