Java中的Lambda表达式与双冒号::的用法

文章目录

  • 1、介绍
  • 2、入门案例
  • 3、语法
  • 4、用法举例
  • 5、精简语法
  • 6、@FunctionalInterface注解
  • 7、双冒号

1、介绍

  • Lamdba是Java1.8的一大亮点,它会使代码更加简洁
  • 通过Lambda,可以代替之前用匿名内部类去实现接口
  • Lambda表达式的本质是一个匿名函数

2、入门案例

定义个接口Calc1,接口中有个求和方法add,按照之前的匿名内部类来new一个接口对象:

Java中的Lambda表达式与双冒号::的用法_第1张图片

以上使用Lambda则是:

Java中的Lambda表达式与双冒号::的用法_第2张图片

匿名内部类被改成了:

Cal c1=(int a,int b) ->{return a+b;};

以上还是未简化的Lambda表达式,还能再简略。

3、语法

Lambda表达式本质上是一个函数(匿名函数),正常定义一个函数或者方法是这样的:返回类型、方法名、参数列表、方法体都有。

int add(int a, int b){
	return a+b;
}

而Lambda表达式则 只留参数列表和方法体。即:

(参数列表) -> { 方法体 }

其中:

  • 圆括号中用来写参数列表
  • -> 是Lamdba运算符,叫做goes to
  • { }花括号中则用来描述方法体

4、用法举例

  • 接口方法无参数无返回值
interface A1{

    /**
     * 无参数无返回值
     */
     void test();
}
A1 a1 = () -> {
	System.out.println("无参数无返回值");
};
  • 接口方法单个参数,无返回值
interface A2{

    /**
     * 单个参数无返回值
     * @param a
     */
    void test(int a);
}
A2 a2 = (int a) -> {
	System.out.println("单个参数无返回值 a = :" + a);
};
  • 接口方法两个参数,无返回值
interface A3{

    /**
     * 两个参数无返回值
     * @param a
     * @param b
     */
    void test(int a,int b);
}
A3 a3 = (int a,int b) -> {
	System.out.println("两个参数无返回值 a+b="+(a+b));
};
  • 接口方法无参数,有返回值
interface A4{

    /**
     * 无参数有返回值
     * @return
     */
    int test();
}
A4 a4 = () -> {	
	System.out.println("无参数有返回值:"+ 1);
	return 1;
};
  • 接口方法单个参数,有返回值
interface A5{

    /**
     * 单个参数有返回值
     * @param a
     * @return
     */
    int test(int a);
}
A5 a5 = (int a) -> {
	System.out.println("单个参数有返回值:"+ a);
	return a;
};
  • 接口方法多个参数,有返回值
interface A6{

    /**
     * 多个参数有返回值
     * @param a
     * @param b
     * @return
     */
    int test(int a,int b);
}
A6 a6 = (int a, int b) -> {
	System.out.println("多个参数有返回值");
	return a+b;
};
a6.test();  //看下效果

5、精简语法

  • 参数类型可省略
  • 一个参数时无需加圆括号(多个参数必须加)
  • 方法体只有一条语句时,花括号可省略
  • 方法体只有一条语句是return返回语句,省略花括号且同时省略return关键字

根据这几条省略规则,上面的lambda表达式可以精简为:

//无参数无返回值
A1 a1 = () -> System.out.println("无参数无返回值");
//单个参数无返回值
A2 a2 =  a -> System.out.println("单个参数无返回值 a = :" + a);
//两个参数无返回值
A3 a3 = (a, b) -> System.out.println("两个参数无返回值 a+b="+(a+b));

接下来是有返回值的,去掉System.out.println这行无用的demo语句:

//无参数有返回值
A4 a4 = () -> {	
	System.out.println("无参数有返回值:"+ 1);
	return 1;
};

//去掉System.out.println这行
A4 a4 = () -> 1;
//单个参数有返回值
A5 a5 = a -> a;
//多个参数有返回值
A6 a6 = (a, b) -> a+b;

6、@FunctionalInterface注解

Java中的Lambda表达式与双冒号::的用法_第3张图片

这个注解用在接口上,标识一个接口为函数式接口,又叫SAM接口,即Single Abstract Method interfaces,即:

  • 这个接口有且仅有一个抽象方法
  • 这个方法允许定义为静态方法
  • 这个方法也允许定义为默认方法
  • 允许java.lang.Object类中的public方法

这种类型的接口,搭配上面的Lambda表达式来创建该接口的对象就很方便。另外,这个注解不是必须的,当一个接口符合函数式接口的定义,那有没有加这个注解都一样,相反,如果不符合却加了这个注解,则编译器报错。

// 正确的函数式接口
@FunctionalInterface
public interface TestInterface {
 
    // 抽象方法
    public void sub();
 
    // java.lang.Object中的public方法
    public boolean equals(Object var1);
 
    // 默认方法
    public default void defaultMethod(){
    
    }
 
    // 静态方法
    public static void staticMethod(){
 
    }
}

// 错误的函数式接口(有多个抽象方法)
@FunctionalInterface
public interface TestInterface2 {

    void add();
    
    void sub();
}

JDK内置了一系列函数式接口,在java.util.function包下:

Java中的Lambda表达式与双冒号::的用法_第4张图片

7、双冒号

英文格式双冒号 ::,double colon。双冒号(::)运算符在Java 8中被用作方法引用(method reference),方法引用是与lambda表达式相关的一个重要特性。

lambda表达式会创建匿名方法,但有时lambda表达式的方法体中除了调用一个现有方法外什么都不做,此时可以直接使用双冒号方法引用。举个栗子:

person -> person.getAge()

方法体就是调用下Person类的get方法,此时可以优化为:

Person::getAge

再比如:

() -> new HashMap<>()

优化为:

HashMap::new

这一点在搭配Stream流写代码时最常用,比如常有把对象通过map转为某一个属性后收集:

dtoList.stream()
		.map(Dto::getId)
		.collect(Collectors.toList());

关于双冒号的六种场景:(注意只是方法名,别加括号)

场景 语法 举例
引用静态方法 类名::静态方法名 Integer::parseInt
引用特定对象的实例方法 对象::实例方法名 System.out::println
引用特定类型的任意对象的实例方法 类名::实例方法名 String::compareToIgnoreCase
引用父类的实例方法 super::方法名
引用类的构造方法 类名::new Person::new
引用数组的构造方法 数组类型[ ]::new String[ ]::new

你可能感兴趣的:(JavaDev,java,Lambda)