HHR的小站
享受代码带来的快乐吧
首页
您正在查看: 语言的魅力 分类下的文章
2021-02-07 |HHR

什么是Stream API

关于stream,IBM对其有一个概括。链接

Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念。它也不同于 StAX 对 XML 解析的 Stream,也不是 Amazon Kinesis 对大数据实时处理的 Stream。Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用 fork/join 并行方式来拆分任务和加速处理过程。通常编写并行代码很难而且容易出错, 但使用 Stream API 无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。所以说,Java 8 中首次出现的 java.util.stream 是一个函数式语言+多核时代综合影响的产物。

怎么使用stream API

获得一个stream对象

对于实现了List接口的对象,获取stream非常简单。

        List<Integer> nums = new ArrayList<>();
        Stream<Integer> stream = nums.stream();

调用Liststream()方法,即可得到一个Stream对象。
而对于int[]一类的数组,获取stream也不是很困难。

        int[] nums = {1, 2, 3, 4, 5, 6, 7};
        IntStream stream = Arrays.stream(nums);

由于Java的基本数据类型导致的问题,此处的stream不再为Stream<T>类型(毕竟int并不是对象),而是一个所谓的IntStream,不过这并不影响其的使用。要获得Stream<Integer>类型的stream,我们只需要将数组更换为Integer[]类型。

        Integer[] nums = {1, 2, 3, 4, 5, 6, 7};
        Stream<Integer> stream = Arrays.stream(nums);

stream有什么用?

获得了一个stream对象之后,我们就可以开始利用它。

求数组长度

最简单的,调用stream.count()方法,即可获得数组的长度。

        Integer[] nums = {1, 2, 3, 4, 5, 6, 7};
        Stream<Integer> stream = Arrays.stream(nums);
        long size = Arrays.stream(nums).count();
        //上下两行代码等价
        size = nums.length;

有人可能会说,就这?这只是stream最简单的使用,接着来些好玩的例子。

统计不及格学生的学号

        Map<String, Integer> score = new HashMap<>();
        score.put("201806061100", 95);
        score.put("201806061101", 75);
        score.put("201806061102", 53);
        score.put("201806061103", 54);
        score.put("201806061104", 77);
        score.keySet().stream()
                .filter(key -> score.get(key) < 60)
                .forEach(key -> System.out.println(key));

该例子使用了stream的filter方法,其中使用了一个lambda表达式,传入一个key,返回key所对应的value是否小于60。这个filter会返回所有成绩低于60分的学生的学号。
接下来,使用了forEach方法,继续利用lambda表达式,将这些学号依次输出。

将stream转回List

        List<String> blame = score.keySet().stream()
                .filter(key -> score.get(key) < 60)
                .collect(Collectors.toList());

使用collect方法,指定转换方式为toList,即可将其转回List<String>

对值进行额外的处理

        score.keySet().stream()
                .filter(key -> score.get(key) < 60)
                .map(key -> key.substring(8))
                .forEach(key->System.out.println(key));

在这里,我们使用了一个新方法 map,可以将其解释为映射.map(key -> key.substring(8)),会返回一个新的stream对象,其中的每一项都执行了 .substring(8)的操作。

排序

        Map<String, Integer> score = new HashMap<>();
        score.put("201806061100", 95);
        score.put("201806061101", 75);
        score.put("201806061102", 53);
        score.put("201806061103", 54);
        score.put("201806061104", 77);
        score.keySet().stream()
                .sorted((k1, k2) -> score.get(k2) - score.get(k1))
                .forEach(key -> System.out.println(key));

使用 sorted方法,并在其中实现一个比较器,即可完成按照成绩从高到低的顺序进行排序。

更多有趣的方法

有关stream的方法还有很多,读者可自行进入Java的文档进行了解,本文不再进行介绍。

2021-02-06 |HHR

引言

一直以来,Java有一个为人所不满的缺点:啰嗦。有些简单的东西,可能需要撰写更多代码才能完成。
幸好,Java为我们推出了很多新功能,来解决其中的问题。本文主要想介绍Java8的lambda表达式。

lambda

之前的版本

先来看这么一串代码

        String[] name = {"Mike", "Tom", "Jerry", "Potty", "Moggy"};
        Arrays.sort(name, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });

有五个小朋友,他们有不同的名字。我们希望按照字母的顺序为其排序。按照Java7的写法,我们需要完成一个Comparator接口,并实现其中的compare方法。以完成排序。

使用lambda的写法

使用IDEA的朋友们可能发现,之前的代码被标为了黄色。IDEA会将你的代码改成这样

Arrays.sort(name, (o1, o2) -> o1.compareTo(o2));

原本的compare函数消失了,变成了 (o1, o2) -> o1.compareTo(o2)。这是怎么回事呢?

什么是lambda

其实这就是lambda表达式,Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用 Lambda 表达式可以使代码变的更加简洁紧凑。
(o1, o2) -> o1.compareTo(o2)意为,传入了o1,o2两个参数,将 o1.compareTo(o2) 的值作为返回值。简单的语法就完成了原本五六行代码的工作量。

还能更简单吗?

能!如果使用Java8的另外一个特性,方法引用,撰写的代码量会更少。有关方法引用的使用,我会在之后的文章里进行介绍。

lambda的更多示例

启动子线程

new Thread(() -> System.out.println("Hello World")).start();

等价于

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello World");
            }
        }).start();

显而易见,使用lambda语句,可以使代码更为简洁。