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. 总结

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

相关文章
|
27天前
|
容器
jdk8新特性-详情查看文档
jdk8新特性-详情查看文档
35 3
|
13天前
|
存储 安全 Java
JDK1.8 新的特性
JDK1.8 新的特性
15 0
|
1月前
|
编解码 安全 Java
jdk8新特性-接口和日期处理
jdk8新特性-接口和日期处理
|
2月前
|
API
JDK8的stream有求和方法吗?
【8月更文挑战第20天】JDK8的stream有求和方法吗?
73 3
|
2月前
|
Java API
JDK8到JDK25版本升级的新特性问题之使用Collectors.teeing()来计算一个列表中学生的平均分和总分如何操作
JDK8到JDK25版本升级的新特性问题之使用Collectors.teeing()来计算一个列表中学生的平均分和总分如何操作
|
2月前
|
Java API Apache
JDK8到JDK24版本升级的新特性问题之在Java中,HttpURLConnection有什么局限性,如何解决
JDK8到JDK24版本升级的新特性问题之在Java中,HttpURLConnection有什么局限性,如何解决
|
2月前
|
Oracle Java 关系型数据库
JDK8到JDK29版本升级的新特性问题之未来JDK的升级是否会成为必然趋势,如何理解
JDK8到JDK29版本升级的新特性问题之未来JDK的升级是否会成为必然趋势,如何理解
|
2月前
|
Oracle 安全 Java
JDK8到JDK28版本升级的新特性问题之在Java 15及以后的版本中,密封类和密封接口是怎么工作的
JDK8到JDK28版本升级的新特性问题之在Java 15及以后的版本中,密封类和密封接口是怎么工作的
|
2月前
|
Java API 开发者
JDK8到JDK17版本升级的新特性问题之SpringBoot选择JDK17作为最小支持的Java lts版本意味着什么
JDK8到JDK17版本升级的新特性问题之SpringBoot选择JDK17作为最小支持的Java lts版本意味着什么
JDK8到JDK17版本升级的新特性问题之SpringBoot选择JDK17作为最小支持的Java lts版本意味着什么
|
1月前
|
Java 编译器 API
JDK8新特性--lambda表达式
JDK8的Lambda表达式是Java语言的一大进步。它为Java程序提供了更多的编程方式,让代码更加简洁,也让函数式编程的概念在Java中得到了体现。Lambda表达式与Java 8的其他新特性,如Stream API、新的日期时间API一起,极大地提高了Java编程的效率和乐趣。随着时间的流逝,Java开发者对这些特性的理解和应用将会越来越深入,进一步推动Java语言和应用程序的发展。
11 0