Lambda表达式你会吗

Java8新特性系列:

Lambda表达式是Java8的一个新特性,使得Java也能进行简单的函数式编程。臃肿的代码轻量化,实现逻辑突出化,可以取代大部分的匿名内部类,写出更优雅的Java代码,尤其在集合的遍历和其他集合操作中,可以极大地优化代码结构。

举个简单栗子:

//常规匿名写法
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("runnable实现常规写法!");
    }
}).start();

//Lambda表达式写法
new Thread(() -> System.out.println("runnable实现lambda写法!")).start();

怎么样?简单吧,一行搞定!下边我就带着大家一起揭开Lambda表达式神秘的面纱。

为什么用Lambda表达式

大家知道Java的开山就是OOP思想,即面向对象,无论干什么事总要产生一个对象来调用相应的方法,而Java中有很多匿名内部类,其实现同样离不开OOP思想,所以也避免不了new出来一个对象实现一个方法这样固定的框架,然而匿名内部类使用的主要目的是方法内部逻辑的实现,那些多写几行的框架似乎对于我们这些猴子来说并不想关心。。。

Lambda表达式正式为解决此类问题而生,Lambda表达式属于函数式编程,以往我们函数的入参需要传递一个对象,现在我们可以直接传入一段逻辑,这就直接省去了生成一个对象的不必要写法,简单到一行代码几个字符就可以搞定一个匿名内部类的实现。

什么时候可以使用Lambda表达式

虽然使用 Lambda 表达式可以对某些接口进行简单的实现,但并不是所有的接口都可以使用 Lambda 表达式来实现。

说到这引申出一个概念——“Function Interface(函数式接口)”。函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口,Lambda表达式只能出现在目标类型为函数式接口的上下文中!

说白了Lambda表达式的目的就是只做一件事,其他花里胡哨的东西不关心,甚至连方法名都不管。

JDK 1.8 之前已有的函数式接口:

    java.lang.Runnable
    java.util.concurrent.Callable
    java.security.PrivilegedAction
    java.util.Comparator
    java.io.FileFilter
    java.nio.file.PathMatcher
    java.lang.reflect.InvocationHandler
    java.beans.PropertyChangeListener
    java.awt.event.ActionListener
    javax.swing.event.ChangeListener

JDK 1.8 新增了一个库包:java.util.function,里面包含很多常用的函数式接口:

JDK1.8新增函数式接口

JDK1.8新增函数式接口场景如下:

Consumer: 消费某个对象
Predicate: 判断对象是否符合某个条件
Function: 实现一个”一元函数“,即传入一个值经过函数的计算返回另一个值
Supplier: 接口仅包含一个无参的方法: T get(),用来获取一个泛型参数指定类型的对象数据
UnaryOperator: UnaryOperator继承了Function,与Function作用相同,不过UnaryOperator,限定了传入类型和返回类型必需相同。

Lambda表达式的基本组成

Lambda表达式由三部分组成:

  1. 形参列表。形参列表允许省略形参类型。如果形参列表中只有一个参数,甚至连形参列表的圆括号也可以省略;
  2. 箭头(->)。必须通过英文中画线和大于符号组成,读作(goes to);
  3. 代码块。如果代码块只包含一条语句,Lambda表达式允许省略代码块的花括号;Lambda代码块只有一条return语句,可以省略return关键字;

Lambda表达式基础语法

下边写六个函数式接口来描述Lambda的基础写法

/**无参无返回值*/
@FunctionalInterface
public interface NoReturnNoParam {
    void method();
}

/**一个参数无返回*/
@FunctionalInterface
public interface NoReturnOneParam {
    void method(int a);
}

/**多参数无返回*/
@FunctionalInterface
public interface NoReturnMultiParam {
    void method(int a, int b);
}

/*** 无参有返回*/
@FunctionalInterface
public interface ReturnNoParam {
    int method();
}

/**一个参数有返回值*/
@FunctionalInterface
public interface ReturnOneParam {
    int method(int a);
}


/**多个参数有返回值*/
@FunctionalInterface
public interface ReturnMultiParam {
    int method(int a, int b);
}

下边是Lambda表达式的基本实现:

public class Test1 {
    public static void main(String[] args) {

        //无参无返回
        NoReturnNoParam noReturnNoParam = () -> {
            System.out.println("NoReturnNoParam");
        };
        noReturnNoParam.method();

        //一个参数无返回
        NoReturnOneParam noReturnOneParam = (int a) -> {
            System.out.println("NoReturnOneParam param:" + a);
        };
        noReturnOneParam.method(6);

        //多个参数无返回
        NoReturnMultiParam noReturnMultiParam = (int a, int b) -> {
            System.out.println("NoReturnMultiParam param:" + "{" + a +"," + + b +"}");
        };
        noReturnMultiParam.method(6, 8);

        //无参有返回值
        ReturnNoParam returnNoParam = () -> {
            System.out.print("ReturnNoParam");
            return 1;
        };

        int res = returnNoParam.method();
        System.out.println("return:" + res);

        //一个参数有返回值
        ReturnOneParam returnOneParam = (int a) -> {
            System.out.println("ReturnOneParam param:" + a);
            return 1;
        };

        int res2 = returnOneParam.method(6);
        System.out.println("return:" + res2);

        //多个参数有返回值
        ReturnMultiParam returnMultiParam = (int a, int b) -> {
            System.out.println("ReturnMultiParam param:" + "{" + a + "," + b +"}");
            return 1;
        };

        int res3 = returnMultiParam.method(6, 8);
        System.out.println("return:" + res3);
    }
}

Lambda表达式语法简化

上边的六个例子是lambda的基本实现,当然还不够精简,接下来由浅入深通过四种简化方式简化一下:

public class Test2 {
    public static void main(String[] args) {

        //1.简化参数类型,可以不写参数类型,但是必须所有参数都不写
        NoReturnMultiParam lamdba1 = (a, b) -> {
            System.out.println("简化参数类型");
        };
        lamdba1.method(1, 2);

        //2.简化参数小括号,如果只有一个参数则可以省略参数小括号
        NoReturnOneParam lambda2 = a -> {
            System.out.println("简化参数小括号");
        };
        lambda2.method(1);

        //3.简化方法体大括号,如果方法条只有一条语句,则可以省略方法体大括号
        NoReturnNoParam lambda3 = () -> System.out.println("简化方法体大括号");
        lambda3.method();

        //4.如果方法体只有一条语句,并且是 return 语句,则可以省略方法体大括号和return关键字
        ReturnOneParam lambda4 = a -> a+3;
        System.out.println(lambda4.method(5));

        ReturnMultiParam lambda5 = (a, b) -> a+b;
        System.out.println(lambda5.method(1, 1));
    }
}

Lambda表达式方法引用简化

方法引用简化

有时候已经有其他方法实现了函数接口的方法了,那么我们可以直接引用此方法代替函数接口的实现方法,常见的引用形式有以下语法:

静态方法引用:ClassName::methodName
实例方法引用:object::methodName
超类方法引用:super::methodName

例如:

public class Exe1 {
    public static void main(String[] args) {
        ReturnOneParam lambda1 = a -> doubleNum(a);
        System.out.println(lambda1.method(3));

        //lambda2 引用了已经实现的 doubleNum 方法
        ReturnOneParam lambda2 = Exe1::doubleNum;
        System.out.println(lambda2.method(3));

        Exe1 exe = new Exe1();

        //lambda4 引用了已经实现的 addTwo 方法
        ReturnOneParam lambda4 = exe::addTwo;
        System.out.println(lambda4.method(2));
    }

    /**
     * 要求
     * 1.参数数量和类型要与函数接口中定义的一致
     * 2.返回值类型要与函数接口中定义的一致
     */
    public static int doubleNum(int a) {
        return a * 2;
    }

    public int addTwo(int a) {
        return a + 2;
    }
}

Exe1中有两个方法,方法的入参和返回值均和函数接口中定义一直,那么这些方法我们可以直接拿来引用,使用形式方法归属者::方法名,入参和返回都不需要显式展现。

构造方法简化

一般我们需要声明接口,该接口作为对象的生成器,通过 类名::new 的方式来实例化对象,然后调用方法返回对象。构造方法简化的语法形式和方法引用简化一样:

构造方法引用:ClassName::new
数组构造引用:TypeName[]::new

例如:

interface ItemCreatorBlankConstruct {
    Item getItem();
}
interface ItemCreatorParamContruct {
    Item getItem(int id, String name, double price);
}

public class Exe2 {
    public static void main(String[] args) {
        ItemCreatorBlankConstruct creator = () -> new Item();
        Item item = creator.getItem();

        ItemCreatorBlankConstruct creator2 = Item::new;
        Item item2 = creator2.getItem();

        ItemCreatorParamContruct creator3 = Item::new;
        Item item3 = creator3.getItem(112, "鼠标", 135.99);
    }
}

最后

相信看到这基本上对Lambda的使用有一定了解了吧,至于网上说Lambda的几个用法:

  • 集合迭代
  • 集合元素删除
  • 集合排序
  • map转换
  • filter过滤

等等,这些其实不属于Lambda的范畴,更多的是java函数属性高级使用,或者是java8新特性的一些高级使用,只不过通过Lambda表达式更加逼格化而已,好了,Lambda深入就到此为止,有时间大伙可以了解以下Java8的流式编程再结合本篇你将受益更多。

我是i猩人,总结不易,转载注明出处,喜欢本篇文章的童鞋欢迎点赞、关注哦。

  • 14
    点赞
  • 44
    收藏
  • 打赏
    打赏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:技术黑板 设计师:CSDN官方博客 返回首页
评论 8

打赏作者

乂星人

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值