资讯专栏INFORMATION COLUMN

JDK8新特性Lambda表达式体验

curlyCheng / 2116人阅读

摘要:的一个大亮点是引入表达式,使用它设计的代码会更加简洁。简介表达式的语法由参数列表箭头符号和函数体组成。表达式示例下面就用一些例子来体验一下表达式。类优惠政策满足的条件,返回接收订单对象,对订单对象进行处理其中接收对象并返回。

“Lambda 表达式”(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Java 8的一个大亮点是引入Lambda表达式,使用它设计的代码会更加简洁。当开发者在编写Lambda表达式时,也会随之被编译成一个函数式接口。

Lambda简介

Lambda表达式的语法由参数列表、箭头符号->和函数体组成。函数体既可以是一个表达式,也可以是一个语句块。

比如:

(int x, int y) -> x + y;

具体的Lambda表达式的介绍可以看这篇博客,写得挺详细的。

Java Lambda表达式示例

下面就用一些例子来体验一下Lambda表达式。

遍历集合

比如我们现在要遍历一个List:

List list = Arrays.asList("Hello", "JDK8", "and", "Lambda");

JDK8之前的写法:

for (String s : list) {
    System.out.println(s);
}

用Lambda表达式写法:

list.forEach(s -> System.out.println(s));

可以看到,无论是代码量和可读性都得到了提高。

在此基础上还可以再用隐式表达式进行简化:

list.forEach(System.out::println);
匿名类

在Java中很多时候我们要用到匿名类,比如线程Runnable、FileFilter和Comparator等等。
而匿名类型最大的问题就在于其冗余的语法。

这里用Comparator做例子。

比如我们有一个Cat类,表示猫,有名字、高度和重量这些属性。

package com.fengyuan.model;

import lombok.AllArgsConstructor;
import lombok.Data;

public @Data @AllArgsConstructor class Cat {
    private String name;
    private double height;
    private double weight;
}

我们创建3只猫,存到List中:

List catList = new ArrayList<>();
// 请无视这些数据的合理性,我乱写的
catList.add(new Cat("cat1", 10.3, 3.6));
catList.add(new Cat("cat2", 9.3, 4.6));
catList.add(new Cat("cat3", 9.5, 4.0));

然后我们现在要对这个List进行排序,但是现在不知道是要怎么排,所以我们要定义一个比较器,指定用高度或者是重量来排序。

JDK8之前的写法:

// 指定用高度来排序
Collections.sort(catList, new Comparator() {
    @Override
    public int compare(Cat o1, Cat o2) {
        if (o1.getHeight() > o2.getHeight()) {
            return 1;
        } else if (o1.getHeight() < o2.getHeight()) {
            return -1;
        } else {
            return 0;
        }
     }
});

而用Lambda,可以这样写:

Collections.sort(catList, (o1, o2) -> {
    if (o1.getHeight() > o2.getHeight()) {
        return 1;
    } else if (o1.getHeight() < o2.getHeight()) {
        return -1;
    } else {
        return 0;
    }
});

继续用方法引用,可以简写到极致:

// 指定用重量排序
catList.sort(Comparator.comparing(Cat::getWeight));
// 要逆向排列也很简单
catList.sort(Comparator.comparing(Cat::getWeight).reversed());

到最后这种写法,已经简写到极致,而且可读性非常高。

函数式接口

JDK8增加了一个新的包:java.util.function,它里面包含了常用的函数式接口,比如Predicate、Consumer,Function等等。

接下来就体验一下Predicate和Consumer的用法。

我们现在有一个订单类,有id,金额,运费这些属性。这个订单有一个折扣方法,我们希望能够根据营销活动,动态修改优惠方案。
Order类:

package com.fengyuan.model;

import java.util.function.Consumer;
import java.util.function.Predicate;

import lombok.AllArgsConstructor;
import lombok.Data;

public @Data @AllArgsConstructor class Order {
    private long id;
    private double payment;
    private double freight;

    // 优惠政策
    public Order discount(Order order, Predicate predicate, Consumer consumer) {
        // 满足Predicate的条件,返回true
        if (predicate.test(order)) {
            // 接收订单对象,对订单对象进行处理
            consumer.accept(order);
        }

        return order;
    }
}

其中

Predicate:接收T对象并返回boolean。

Consumer:接收T对象,没有返回值。

然后通过函数式编程,我们可以动态传入我们的优惠方案,比如99包邮:

// 新建一个订单,506.5的金额,10.0的运费
Order order = new Order(123, 506.5, 10.0);
// 满足金额>=99的条件,则设置运费为0
order.discount(order, 
        o -> o.getPayment() >= 99, 
        o -> o.setFreight(0));

这样一来,就能根据营销活动,修改我们的优惠方案。

除此之外,Predicate对象之间还能运用与或非这些逻辑操作,比如:

predicate1.and(predicate2);
predicate1.or(predicate2);
Stream

这里的Stream和I/O流不同,它更像具有Iterable的集合类。

Stream API引入的目的在于弥补Java函数式编程的缺陷,让java也支持map()、reduce()等函数式编程语言。

map

map(映射),将传入的函数依次作用到序列的每个元素。

比如说,有一个字符串列表,我们现在给列表里每个字符串调用toLowerCase()方法,转成小写字母。

List list = Arrays.asList("Hello", "JDK8", "and", "Lambda");

转成小写,用collect()把Stream再转回List,返回新的列表:

List newList = list.stream().map(s -> s.toLowerCase()).collect(Collectors.toList());

也可以返回一个字符串,指定连接符,我这里是用空格连接的:

String str = list.stream().map(s -> s.toLowerCase()).collect(Collectors.joining(" "));

也可以用隐式函数,String::toLowerCase来实现:

String str = list.stream().map(String::toLowerCase).collect(Collectors.joining(" "));
reduce

reduce(归约),将集合中所有值结合起来。

将一个整型List,先进行map:每个数都翻一倍,再进行reduce:所有数加起来,得到结果:

        List numbers = Arrays.asList(10, 20, 30, 40, 50);
        int result = numbers.stream().map(num -> num * 2).reduce((r, num) -> r += num).get();
变量捕捉

一个简单的例子,算出一个集合中最大值、最小值、平均值等等。

集合:

List numbers = Arrays.asList(4, 6, 65, 3, 44, 2, 17, 19);

计算:

int max = numbers.stream().mapToInt(x -> x).max().getAsInt();
int min = numbers.stream().mapToInt(x -> x).min().getAsInt();
long count = numbers.stream().mapToInt(x -> x).count();
double avg = numbers.stream().mapToInt(x -> x).average().getAsDouble();
int sum = numbers.stream().mapToInt(x -> x).sum();

也可以用IntSummaryStatistics类来得到统计结果:

IntSummaryStatistics stat = numbers.stream().mapToInt(x -> x).summaryStatistics();
int max = stat.getMax();
int min = stat.getMin();
long count = stat.getCount();    
double avg = stat.getAverage();
long sum = stat.getSum();
结语

虽然平时项目的开发中还是比较少用到Lambda表达式,但是在以上这些体验中,确实是感受到了它的魅力。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/65072.html

相关文章

  • 认识JDK8特性Lambda达式

    摘要:说来挺惭愧的,已经出来这么多年,在实际项目中却很少真正使用表达式。举个简单例子对于无参无返回值,可以有如下写法前的一对小括号和后面的一对大括号都不能去掉。表达式不会定义新的作用域表达式的作用域与封闭作用域相同。 说来挺惭愧的,JDK8已经出来这么多年,在实际项目中却很少真正使用Lambda表达式。其实工作中的项目很早就从开发、测试、生产,全面使用JDK8+Tomcat8了。 所以看来是...

    awesome23 评论0 收藏0
  • 转 | Java8初体验(一)lambda达式语法

    摘要:初体验下面进入本文的正题表达式。接下来展示表达式和其好基友的配合。吐槽一下方法引用表面上看起来方法引用和构造器引用进一步简化了表达式的书写,但是个人觉得这方面没有的下划线语法更加通用。 感谢同事【天锦】的投稿。投稿请联系 tengfei@ifeve.com 本文主要记录自己学习Java8的历程,方便大家一起探讨和自己的备忘。因为本人也是刚刚开始学习Java8,所以文中肯定有错误和理解偏...

    Lucky_Boy 评论0 收藏0
  • 【全栈之路】JAVA基础课程十一_JDK8十大特性(20190706v1.2)

    摘要:欢迎进入基础课程博客地址本系列文章将主要针对一些基础知识点进行讲解,为平时归纳所总结,不管是刚接触开发菜鸟还是业界资深人士,都希望对广大同行带来一些帮助。语法是,或者更一般的,要求构造器方法是没有参数静态方法引用。 欢迎进入JAVA基础课程 博客地址:https://blog.csdn.net/houjiyu...本系列文章将主要针对JAVA一些基础知识点进行讲解,为平时归纳所总结,...

    lcodecorex 评论0 收藏0
  • 【全栈之路】JAVA基础课程十一_JDK8十大特性(20190706v1.2)

    摘要:欢迎进入基础课程博客地址本系列文章将主要针对一些基础知识点进行讲解,为平时归纳所总结,不管是刚接触开发菜鸟还是业界资深人士,都希望对广大同行带来一些帮助。语法是,或者更一般的,要求构造器方法是没有参数静态方法引用。 欢迎进入JAVA基础课程 博客地址:https://blog.csdn.net/houjiyu...本系列文章将主要针对JAVA一些基础知识点进行讲解,为平时归纳所总结,...

    VPointer 评论0 收藏0
  • lambda达式一,介绍

    摘要:体验的更优写法借助的全新语法,上述接口的匿名内部类写法可以通过更简单的表达式达到等效多线程任务执行启动线程这段代码和刚才的执行效果是完全一样的,可以在或更高的编译级别下通过。 jdk8 2014年加入了lambda表达式实例代码 showImg(https://segmentfault.com/img/bVbwb0V); showImg(https://segmentfault.com...

    ybak 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<