java基础复习(3)

写在前面

前面学习了Lambda表达式,现在来学习一下根据Lambda表达式衍生出的Stream流和方法引用。

Stream流

引子

一提到流,可能都只会想到IO流。实际上,流不一定是IO流,今天就来学习一下Stream流。首先我们来看一段传统的集合过滤代码:

        // 创建一个List集合,存储姓名
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");

        // 对集合中的元素进行过滤,只要以张开头头的元素都存到一个新的集合中
        List<String> listA = new ArrayList<>();
        for (String s : list) {
            if(s.startsWith("张")){
                listA.add(s);
            }
        }
        // 对listA集合进行过滤,只要姓名长度为3的人,再存到一个新集合中
        List<String> listB = new ArrayList<>();
        for (String s : listA) {
            
            if (s.length() == 3) {
                listB.add(s);
            }
        }
        // 遍历listB集合
        for (String s : listB) {
            System.out.println("s = " + s);
        }

在这段代码中,我们先选出了姓张的,再选出了姓名长度为3的,最后使用增强for循环进行了输出。可以看到代码还是很多的。那么我们如果使用Stream流呢?

        // 创建一个List集合,存储姓名
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");
        // 对集合中的元素进行过滤,只要以张开头头的元素都存到一个新的集合中
        // 对listA集合进行过滤,只要姓名长度为3的人,再存到一个新集合中
        // 遍历listB集合
        list.stream()
                .filter(name -> name.startsWith("张"))
                .filter(name -> name.length() == 3)
                .forEach(name -> System.out.println(name));

可以看到,我们的代码被极大简化了。这就是结合了Stream流和Lambda表达式给我们带来的编程便利。

获取Stream流

既然这东西这么好,那我们如何获取和使用呢?这里我们学习以下两种获取方法:

  1. 使用集合直接获取
  2. 使用Stream.of静态方法获取。

直接上例子看看:

    public static void main(String[] args) {
        // 把集合转换成Stream流
        List<String> list = new ArrayList<>();
        Stream<String> stream1 = list.stream();
        Set<String> set = new HashSet<>();
        Stream<String> stream2 = set.stream();
        Map<String,String> map = new HashMap<>();
        // 获取键,存储到一个Set集合中
        Set<String> keySet = map.keySet();
        Stream<String> stream3 = keySet.stream();
        // 获取值,存储到一个Collection集合中
        Collection<String> values = map.values();
        Stream<String> stream4 = values.stream();
        // 获取键值对(键与值的映射关系 entrySet)
        Set<Map.Entry<String, String>> entries = map.entrySet();
        Stream<Map.Entry<String, String>> stream5 = entries.stream();

        // 把数组转换为Stream流
        Stream<Integer> stream6 = Stream.of(1, 2, 3, 4, 5);
        // 可变参数可以传递数组
        Integer[] arr = {1,2,3,4,5};
        Stream<Integer> stream7 = Stream.of(arr);
        String[] arr2 = {"a","bb","cccc"};
        Stream<String> stream8 = Stream.of(arr2);
    }

可以看到,Stream流的获取还是十分简单的。那么我们可以用Stream流做到什么呢?

Stream流里的常用方法

首先要了解,Stream流的方法有两种,一种叫延迟方法(即返回的还是Stream接口自身),一种叫终结方法,返回的类型就不再是Stream接口自身了。

  • forEach(终结方法)

    虽然叫forEach,但和增强for循环还是不太一样的。我们来看看怎么使用:

          // 获取一个Stream流
            Stream<String> stream = Stream.of("张三", "李四", "王五", "赵六");
            // 使用Stream流中的方法
            stream.forEach(name -> System.out.println("name = " + name));
            System.out.println("===========");
    
  • filter(延迟方法)

    这是我们刚才使用的filter方法,我们来再使用一次看看:

            // 创建Stream流
            Stream<String> stream1 = Stream.of("张三锋", "李四", "王五", "赵六");
            // 对Stream流中的元素进行过滤出姓张的
            Stream<String> stream2 = stream1.filter(name -> name.startsWith("张"));
            // 遍历stream1
            stream2.forEach(name -> System.out.println(name));
    
  • map(延迟方法)

    map方法,可以进行集合进行转换,如下使用:

            // map方法
            // 获取Stream流
            Stream<String> stream3 = Stream.of("1", "2", "3");
            // 使用map方法将字符串转换为Ineger类型的整数
            Stream<Integer> stream4 = stream3.map(s -> Integer.parseInt(s));
    
  • collect(终结方法)

    首先我们要有一个对象:

    public class Person {
        
        private String name;
        private int age;
    }
    

    里面的get,set方法和构造方法就省略了。

    然后我们使用collect方法:

            List<Person> list1 = new ArrayList<>();
            list1.add(new Person("王五",15));
            list1.add(new Person("赵四",18));
            list1.add(new Person("赵六",20));
            Map<String, Integer> map = list1.stream().collect(Collectors.toMap(p -> p.getName(), p->p.getAge()));
    

    可以看到,我们使用Stream流可以很方便的将一个List转换成了一个map。同样的,也可以先处理后转换成List,Set等等。具体的使用请在实际使用中练习吧。

方法引用

引子

上面我们的使用,实际上已经十分简单了,但能不能更简单呢?可以看到有时候我们的Lambda表达式都只用了一句话,比如下面的这个:

.forEach(name -> System.out.println(name));

这里面的name实际上没有任何意义,只是我们定义的一个形参而已。我们想要的就是输出这个形参罢了。那么我们可以写成下面这样:

.forEach(System.out::println);

是不是更加简单了呢?

介绍和使用

这里出现了一个新的符号,双冒号。学过C++的可能会知道,这个符号在C++里叫做作用域符,有一种用法和上面也很像,如类::变量。但在java中这个叫做引用运算符,如果在Lambda表达式中要表达的函数方法已经存在,那么就可以使用这个符号来调用他。

事实上,我们自己定义的方法也可以用,比如上面我们提到的collect方法,我们也可以用方法引用这么写:

        Map<String, Integer> map = list1.stream().
                collect(Collectors.toMap(Person::getName, Person::getAge));

看起来是不是要简单的多了呢。

小结

方法引用的使用方法和场景多种多样,这里只介绍最基本的用法,具体的就请在日后使用到时再了解吧。

总结

这里学习的这些,都是JDK8里的新特性。通过这些新特性的学习,我们可以让代码更加的优雅了。

posted @ 2020-07-21 23:41  武神酱丶  阅读(105)  评论(0编辑  收藏  举报