文章目录

  • 概述
  • 优势
  • 示例
  • 释义
  • 拓展示例
  • 示例1
  • 示例2
  • 变量作用域
  • 方法变量
  • 类变量
  • 结尾语


概述

现在,很多同学已经接受并熟悉了 Java 的 Lamda 写法,但可能有些同学还是一头雾水。
这里,我抛砖引玉,来对 Java Lamda 写法做一个简单的介绍:

  • 首先 Lamda 写法的固定格式为:参数 -> 语句块
  • 另外 Lamda 语法是出现在Java8及其以后的,Java8以前是不涉及的,所以JDK1.7及其以前版本这种写法编译是会被报错的。
优势

那么Lamda 写法有哪些优势呢?

  • 首先,他简化了代码,将以前很多行的代码简化为几行或者一行,使得代码看上去更加的简介;
  • 另外,Lamda 算法对并行运算非常具有优势,某些实现用 Lamda 方式会更加高效。
示例

如果一个接口只有一个实现方法,我们称这种接口叫做函数式接口。
那么我们通常会以匿名内部类的方式去实现。

比如:我们常用的多线程去异步实现某个功能的时候,常常会使用如下方式:

new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("异步功能实现");
    }
}).start();

这里的 Runable 接口就一个run() 实现方法,源码如下图:

java rabbitmq异步消费ack_System

那么这种条件下,就可以简化为 Lamda 写法,具体效果如下:

new Thread(() -> System.out.println("异步实现功能")).start();

我们可以看见:Lamda 写法的代码量已经浓缩为了一行,确实简洁了不少。

释义

那么如何理解上面这句 Lamda 写法呢?

(1)我们可以看到,变化的只是参数接口匿名实现类的写法,外面外并未有任何变化;

(2)由于 Thread 类里面就一个以接口为参数的方法,所以省去了接口名 Runable;

(3)由于 Ruanble 接口里面就一个 run() 方法定义,故而省去了方法名;

(4)由于 run() 方法定义里未有任何参数,故而 Lamda 写法就只有以一个 () 开头了;

(5) 中间的箭头 -> 是 Lamda 标识符,读作 “goes to”;

(6)箭头后面就是实现方式了,这个同以前代码实现。

拓展示例
示例1

那么,当一个接口的唯一方法涉及多个参数,此时 Lamda 写法又该怎么样呢?

我们不妨创建一个 MyService,里面包含一个带有参数的方法定义:

public  interface MyService {

	public void say(String name);

}

然后我们创建一个 Test 类,并在类里面添加一个该接口为参数的 test() 方法,以及主方法进行测试:

Java 8 以前的写法:

public class Test {

    public static void main(String[] args){
        test(new MyService() {
            @Override
            public void say(String name) {
                System.out.println("hello : " + name);
            }
        });
    }
    
    public static void test(MyService service) {
        service.say("jack");
    } 

}

程序运行结果为如下所示:

java rabbitmq异步消费ack_System_02

Java 8 Lamda 写法:

public class Test {

    public static void main(String[] args){
        test((name) -> System.out.println("hello : " + name));
    }
    
    public static void test(MyService service) {
        service.say("jack");
    } 

}

运行结果,同样为:

java rabbitmq异步消费ack_System_03

经过上面两个例子,我们已经证实了,两种写法的运行效果完全是可以等价的,Lamda 写法看起来也更简洁。

另外,当参数只有一个的时候,参数的括号也可以省去不写,例如,上面的 Lamda 写法还可以进一步简写:

test(name -> System.out.println("hello : " + name));

同理,如果接口的方法有多个参数的时候,Lamda 参数括号里也需要传递多个参数。

示例2

我们将接口里面的 say(String name) 方法,增加一个参数 age,改为如下:

public interface MyService {

    public void say(String name, int age);

}

那么对应的方法调用就成为了如下:

Java 8 前写法:

public class Test {

	public static void main(String[] args){
		test(new MyService() {
			@Override
			public void say(String name, int age) {
				System.out.println("hello : " + name + ", I am " + age);
			}
		});
	}
	
	public static void test(MyService service) {
		service.say("jack", 28);
	} 

}

Java 8 Lamda 写法:

public class Test {

	public static void main(String[] args){
		test((name, age) -> System.out.println("hello : " + name + ", I am " + age));
	}
	
	public static void test(MyService service) {
		service.say("jack", 28);
	} 

}

两种写法的输出结果都是:

java rabbitmq异步消费ack_System_04

可以看到,随着接口方法 say() 里的参数增加,Lamda 参数括号里面的参数也相应增加。

同理,当 Lamda 语句块里面只有一条语句的时候,我们可以通常省略语句块符号{},如上面的 Lamda语句:

test((name, age) -> System.out.println("hello : " + name + ", I am " + age));

但如果涉及多条语句的时候,就需要增加语句块 {}了,比如我们将 name 和 age 分别打印的话,则对应的 Lamda 写法为:

test((name, age) -> {
	System.out.println("My name is"+ name);
	System.out.println("I am "+ age);
});
变量作用域
方法变量

首先,Lamda 语句中引用外层方法中的变量的时候,是不允许修改其变量值的,具体什么意思呢?我们不妨接着往下看。

我们在上一步中的方法增加一个变量;

java rabbitmq异步消费ack_System_05


然后我们在 Lamda 语句块中将其值修改下:

java rabbitmq异步消费ack_Java_06


可以看到:编译器这时候报了错,说明其值是不允许被修改的:

这就说明: Lamda 不允许修改所在外层方法里的变量;

类变量

然后,我们将变量的位置挪动下,将方法变量移动到为类的变量(这里由于方法是 static 的,所以我们为了能直接访问到变量,也加上 static 修饰)。

java rabbitmq异步消费ack_Test_07


可以看到,这时编译器并未进行报错,说明 Lamda 语句块中是可以修改其类成员变量(final 修饰除外)。我们运行程序:

java rabbitmq异步消费ack_System_08


可以看到,确实是我们修改后的值。

结尾语

上面所讲的主要是 Lamda 写法之匿名内部类,这是一个较为容易理解 Lamda 写法的入门,谢谢大家!