java8—Lambda,Stream,Function

作者: 激情的狼王 | 来源:发表于2018-03-29 13:09 被阅读108次

    java8推出了很多更新,但是在编码方面,总结起来我认为有三大块:Lambda语法,Stream包,Function包。

    Lambda语法

    基本语法:

    (parameters) -> expression
    (parameters) ->{ statements; }

    假设有一个玩家List ,程序员可以使用 for 语句 ("for 循环")来遍历,在Java SE 8中可以转换为另一种形式:

    // 以前的循环方式  
    for (String player : players) {  
         System.out.print(player + "; ");  
    }  
      
    // 使用 lambda 表达式以及函数操作(functional operation)  
    players.forEach((player) -> System.out.print(player + "; "));  
    

    正如您看到的,lambda表达式可以将我们的代码缩减到一行。 下面是使用lambdas 来实现 Runnable接口 的示例:

    // 1.1使用匿名内部类  
    new Thread(new Runnable() {  
        @Override  
        public void run() {  
            System.out.println("Hello world !");  
        }  
    }).start();  
      
    // 1.2使用 lambda expression  
    new Thread(() -> System.out.println("Hello world !")).start();  
      
    // 2.1使用匿名内部类  
    Runnable race1 = new Runnable() {  
        @Override  
        public void run() {  
            System.out.println("Hello world !");  
        }  
    };  
      
    // 2.2使用 lambda expression  
    Runnable race2 = () -> System.out.println("Hello world !");  
    

    lambda表达式可以将多行代码转换成单行语句。

    Stream使用

    Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。

    Stream提供串行(stream)和并行(parallelStream)两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用 fork/join 并行方式来拆分任务和加速处理过程。通常编写并行代码很难而且容易出错, 但使用 Stream API 无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。所以说,Java 8 中首次出现的 java.util.stream 是一个函数式语言+多核时代综合影响的产物。

    在 Java 7 中,如果要发现 type 为 grocery 的所有交易,然后返回以交易值降序排序好的交易 ID 集合,我们需要这样写:

    List < Transaction > groceryTransactions = new Arraylist < > ();
    for (Transaction t: transactions) {
        if (t.getType() == Transaction.GROCERY) {
            groceryTransactions.add(t);
        }
    }
    Collections.sort(groceryTransactions, new Comparator() {
        public int compare(Transaction t1, Transaction t2) {
            return t2.getValue().compareTo(t1.getValue());
        }
    });
    List < Integer > transactionIds = new ArrayList < > ();
    for (Transaction t: groceryTransactions) {
        transactionsIds.add(t.getId());
    }
    

    而在 Java 8 使用 Stream,代码更加简洁易读;而且使用并发模式,程序执行速度更快。

    List<Integer> transactionsIds = transactions.parallelStream().
         filter(t -> t.getType() == Transaction.GROCERY).
         sorted(comparing(Transaction::getValue).reversed()).
         map(Transaction::getId).
         collect(toList());
    

    我们可以看出来,stream提供了filter、sorted、map、collect等通俗易懂的方法来解决汇聚问题来看下它的API

    QQ图片20180329124016.png
    除了上述的几个方法外,还有limit、min、distinct等实用的方法供我们来调用。
    注意:

    这些方法的入参是需要一系列的比较器(Ccompare)、Boolean返回器(Predicate)、Function等工具的,这些就是下面的Function包的内容了。

    再来看一个limit/skip的使用,limit 返回 Stream 的前面 n 个元素;skip 则是扔掉前 n 个元素

    public void testLimitAndSkip() {
        List < Person > persons = new ArrayList();
        for (int i = 1; i <= 10000; i++) {
            Person person = new Person(i, "name" + i);
            persons.add(person);
        }
        List < String > personList2 = persons.stream().
        map(Person::getName).limit(10).skip(3).collect(Collectors.toList());
        System.out.println(personList2);
    }
    private class Person {
        public int no;
        private String name;
        public Person(int no, String name) {
            this.no = no;
            this.name = name;
        }
        public String getName() {
            System.out.println(name);
            return name;
        }
    }
    

    输出结果

    name1
    name2
    name3
    name4
    name5
    name6
    name7
    name8
    name9
    name10
    [name4, name5, name6, name7, name8, name9, name10]
    

    Function包

    java.util.function包下面有大量的函数式接口,主要分为以下几个基本类别

    Function 输入参数为类型T, 输出为类型R, 记作 T -> R
    Consumer 输入参数为类型T, 输出为void, 记作 T -> void
    Supplier 没有输入参数, 输出为类型T, 记作 void -> T
    Predicate 输入参数为类型T, 输出为类型boolean, 记作 T -> boolean

    例如计算字符串长度的Function例子

    Function<String, Integer> fc = s -> s.length();
    

    再例如,切割字符串的Consumer

    Consumer<String> consumer = c -> c.split(",");
    

    如果输入参数是两个,这是可以使用

    BiFunction<T,U,R> 记作 <T,U> -> R
    BiConsumer<T,U> 记作 <T,U> -> void
    BiPredicate<T,U> 记作 <T,U> -> boolean

    全部的Function接口可以查看Function包下的API:


    QQ图片20180329125520.png

    使用forEach方法,增加java和php程序员的工资5%:

    System.out.println("给程序员加薪 5% :");  
    Consumer<Person> giveRaise = e -> e.setSalary(e.getSalary() / 100 * 5 + e.getSalary());  
      
    javaProgrammers.forEach(giveRaise);  
    phpProgrammers.forEach(giveRaise);  
    

    本文只是简单介绍了基本的用法,更多的组合操作还需在实践中摸索。

    相关文章

      网友评论

        本文标题:java8—Lambda,Stream,Function

        本文链接:https://www.haomeiwen.com/subject/fllmcftx.html