Lambda表达式

Posted 行则将至

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Lambda表达式相关的知识,希望对你有一定的参考价值。

看mybatis-plus的时候,使用mybatisplus的自动填充,拿官方代码拷到自己的环境上时Idea提示warning


直接altenter,会修改成两个冒号的形式,两种都是lambda表达式的写法,没见过,开贴记录


Lambda表达式

一、简介

Lambda表达式时JDK8的一个新特性(现在都JDK17了(´・_・`)),可以取代大部分的匿名类,写出更优雅的代码。

二、使用范围

Lambda规定接口中只能有一个需要被实现的方法 ,除此之外,jdk8中另一个特性,default,被default修饰的方法会有默认实现,不是必须被实现的方法,因此不影响Lambda表达式的使用

三、函数式接口

如果一个接口中只有一个需要实现的方法,那么这个接口就是函数式接口,@FunctionalInterface注解诞生!该注解用来判断接口是否为函数式接口,为Lambda表达式服务

不是函数式接口

函数式接口

四、初体验~

1.接口

@FunctionalInterface
public interface LambdaInterface {
    abstract void method(Integer num);
    default void method2(){
        System.out.println("this is method2");
    }
}

2.实现接口(JDK5)

public class LambdaTest {
    public static void main(String[] args) {
        new LambdaInterface() {
            // 匿名内部类
            @Override
            public void method(Integer num) {
                System.out.println(num);
            }
        };
    }
}

3.实现接口(JDK8)

public class LambdaTest {
    public static void main(String[] args) {
        //Lambda表达式 ()->{}
        LambdaInterface lambdaInterface = (Integer num)->{
            System.out.println(num);
        };
    }
}

五、Lambda简化写法

1.简化参数类型

传入两个参数,可以省略参数类型,参数类型可以不同,如a为Integer,b为String,可以直接省略

        LambdaInterface lambdaInterface = (a,b)->{
            System.out.println(a);
        };

2.简化参数括号

只有一个参数,可以省略参数括号

        LambdaInterface lambdaInterface = b->{
            System.out.println(b);
        };

3.简化方法体括号

如果方法体中只有一条语句,可以省略大括号,和ifelse一样

        LambdaInterface lambdaInterface = b->System.out.println(b);

4.简化方法体

如果方法体中只有return语句,则可直接省略return关键字

        LambdaInterface lambdaInterface = (a,b)->a;

六、Lambda应用

遍历集合

  • 定义集合
        List<String> list = Arrays.asList("Java","C++","Python","php");
  • for遍历
        for (String s : list) {
            System.out.println(s);
        }
  • forEach遍历

标准的函数式接口!

里面还是fro循环,参数看不懂,他需要一个T我们直接传一个t,打印

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


打印出了集合中的信息!

  • 简化
        list.forEach(System.out::println);

七、JDK8 方法引用

1.静态方法引用(static method)

  • 语法:classname::methodname 例如:Person::getAge

2.对象的实例方法引用

  • 语法:instancename::methodname 例如:System.out::println

3.对象的超类方法引用

  • 语法: super::methodname

4.类构造器引用

  • 语法: classname::new 例如:ArrayList::new

5.数组构造器引用

  • 语法: typename[]::new 例如: String[]:new

详解:https://blog.csdn.net/zhoufanyang_china/article/details/87798829

  • 例子
@FunctionalInterface
interface Supplier<T> {
    T get();
}
public class LambdaTest {
    public static void main(String[] args){
        User user = LambdaTest.create(User::new);
        System.out.println(user);
    }
    public static User create(final Supplier<User> supplier) {
        return supplier.get();
    }

}

Lambda表达式中的表达式lambda和语句lambda区别

Lambda表达式可分为表达式lambda和语句lambda

表达式lambda:表达式位于 => 运算符右侧的lambda表达式称为表达式lambda

(input parameters) => expression     //表达式lambda

例如

(x, y) => x == y

语句lambda:=> 运算符右侧是一个语句块,语句包含在大括号中

(input parameters) => {statement;}  //语句lambda

例如:

(x, y) => {return x == y;}

这两者除了写法不一样,还有什么区别吗,用以下代码作为测试

复制代码
using System;
using System.Collections.Generic;

namespace LinqTest
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> list = new List<int> { 1, 3, 2, 4 };
            var resultUsingExpressionLambda = list.FindAll(p => p < 3);
            Console.WriteLine("使用表达式lambda:");
            foreach (var item in resultUsingExpressionLambda)
            {
                Console.WriteLine(item);
            }
            var resultUsingStatementLambda = list.FindAll(p =>
            {
                return p < 3;
            });
            Console.WriteLine("使用语句lambda:");
            foreach (var item in resultUsingStatementLambda)
            {
                Console.WriteLine(item);
            }
        }
    }
}
复制代码

代码比较简单,就是分别使用表达式lambda和语句lambda找出小于3的数,然后输出来,结果如下

image

输出结果一样。

查看反编译后的代码

image

看来编译器做了处理,两者的代码都是一样了,既然这样,那么在语句lambda中多加一行代码,Console.WriteLine(p); 这样就不会生成一样的代码了

Console.WriteLine(p.ToString());

复制代码
using System;
using System.Collections.Generic;

namespace LinqTest
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> list = new List<int> { 1, 3, 2, 4 };
            var resultUsingExpressionLambda = list.FindAll(p => p < 3);
            Console.WriteLine("使用表达式lambda:");
            foreach (var item in resultUsingExpressionLambda)
            {
                Console.WriteLine(item);
            }
            var resultUsingStatementLambda = list.FindAll(p =>
            {
                Console.WriteLine(p);//这是新加的
                return p < 3;
            });
            Console.WriteLine("使用语句lambda:");
            foreach (var item in resultUsingStatementLambda)
            {
                Console.WriteLine(item);
            }
        }
    }
}
复制代码

再查看反编译后的代码

image

再来看下IL代码

image

 

image

可以看到,无论是表达式lambda还是语句lambda,最后都生成一个方法,这里生成的方法分别是imageimage,然后将方法赋给委托变量,就是这部分:

image

所以,给委托变量赋值时,表达式lambda和语句lambda写法不一样,但是最后编译器都生成一个方法。

还有个不同点,表达式lambda可以转换为类型Expression<T>的表达式树,而语句lambda不可以

Expression<Func<int, int, int>> expression = (a, b) => a + b;//正确
Expression<Func<int, int, int>> expression1 = (a, b) => { return a + b; };//错误,无法将具有语句体的 lambda 表达式转换为表达式树                  

 

//但是他们都可以赋给一个Func

Func<int, int, int> fun = (a, b) => a + b;//正确
Func<int, int, int> fun1 = (a, b) => { return a + b; };//正确

以上是关于Lambda表达式的主要内容,如果未能解决你的问题,请参考以下文章

JAVA由一个将JSONArray转成Map的需求引发的lambda语法的学习

函数式编程

C# fun

Lambda表达式

Lambda表达式

Lambda表达式