一文带你读懂Lamdba表达式

Lambda表达式的实质,是一个可传递的代码块
(也可以称之为闭包)


eg.最简单的一个lambda表达式
	参数->{表达式}
	(String first,String second)->{
	if(first.length()<second.length())
			return -1;
	else if(first.length()>second.length())
			return 1;
	else 
			return 0;
	}
	即使lambda表达式没有参数,仍然要提供空括号,就像无参方法
()->{
for(int i=0;i<=100;i++)
	System.out.println(i);
}
package lambda;

import java.util.Arrays;
import java.util.Date;

import javax.swing.JOptionPane;
import javax.swing.Timer;

public class LambdaTest {
	public static void main(String []args) {
		String []plants= {"Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune"};
		System.out.println(Arrays.toString(plants));
		
		System.out.println("Sorted by dictionary order:");
		Arrays.sort(plants);
		System.out.println(Arrays.toString(plants));
		
		
		System.out.println("Sorted by length:");
		Arrays.sort(plants,(first,second)->first.length()-second.length());
		System.out.println(Arrays.deepToString(plants));
	
		Timer t=new Timer(1000,event->{
			System.out.println("The time now is"+new Date());
		});
		t.start();	
		
		
		Timer t1=new Timer(1000,System.out::println);	//方法引用
		t1.start();										//等价于lambda表达式 x->System.out.println(x)
		
		
		
		JOptionPane.showMessageDialog(null, "Quit?");	//让程序不关闭
		System.exit(0);
		
	}	
}


这段代码的运行结果为

在这里插入图片描述


方法的引用

					
使用::操作符分隔类名和方法名
	 一般
	 Objecet::instanceMethod
	 Class::staticMethod
	 Class::instanceMethod

使用this::method和super::method也是合法的
对于前两种方法,等价于提供方法参数的lambda表达式
System.out.println等价于   x->System.out.println(x);
Math::pow		  等价于  (x,y)->Math.pow(x,y)

对于第三种方法,第一个参数为成为方法的目标
String::compareToIgnoreCase
等同于
(x,y)->x.compareToIgnoreCase(y);

构造器的引用

构造器引用和方法引用类似,不过方法名为new

ArrayList<String>names={...};
Stream<Person> stream=names.stream().map(Person::new);
List<Person>people=stream.collect(Collectors.toList());

map方法会各个列表元素Person,调用Person构造器,如果有多个Person构造器,编译器会根据上下文推导选择一个有String参数的构造器

也可以使用数组类型建立构造器引用
eg.
	int[]::new
	等价于lambda表达式中
	x->new int[x]


变量作用域

当你希望在lambda表达式中访问外围的方法或变量时

package lambda;

import java.awt.Toolkit;
import java.awt.event.ActionListener;

import javax.swing.JOptionPane;
import javax.swing.Timer;

public class LambdaTest {
	public static void main(String []args) {
	
		repeatMessage("Good",1000);
		JOptionPane.showMessageDialog(null, "Quit?");	//让程序不关闭
		System.exit(0);
		
	}
	public static void repeatMessage(String text,int delay) {
		ActionListener listener=event->{
			System.out.println(text);
			Toolkit.getDefaultToolkit().beep();
		};
		new Timer(delay, listener).start();;
	}	
}

可以看到,变量text并不是lambda表达式中的变量,而是方法repeatMessage中的变量,
但是lambda表达式的代码可能在函数调用返回很久之后才运行,
而那时这个参数变量已经不存在了,如何保留text变量呢?

Iambda表达式中有三个部分
	1) 代码块
	2)参数
	3)自由变量的值(不在代码块中定义的变量)

比如上文的text就是一个自由变量
我们说它被lambda表达式捕获
(一个lambda表达式转换成包含一个方法的对象,这样,自由变量就会复制到这个对象的实例变量中)

但是!!!!

即使lambda表达式可以捕获自由变量,但是这个自由变量必须是明确定义的(值不会改变

public static void countDown(int start,int delay) {
		ActionListener listener=a->{
			start--;						//Error,can't capture
			System.out.println(start);
		};
		new Timer(delay,listener).start();
	}
public static void repeat(String text,int ocunt){
	for(int i=1;i<=count;i++)
		{
			ActionListener listener=event->{
			System.out.println("i="+i); 	//Error,can't capture
			};
			new Timer(1000,listener).start();
		}
	}

之所以如此,是因为如果 并发执行 多个lambda表达式就会 不安全
此外,如果自由变量的值在外部改变也同样不合法

Lambda表达式中捕获的变量必须是最终变量(effctively final)

处理lambda表达式

lambda表达式的重点延迟执行
将某个函数包装在一个lambda表达式中,是希望在以后再执行

	之所以希望它以后执行的原因有
		1.在一个   单独的线程   中运行
		2.多次运行代码
		3.在算法中的某个具体位置调用
		4.发生某种特定情况时(eg.触发器)

例如想要重复执行某代码如下

repeat(10,()->System.out.println("Hello "))

要想接受这个lambda表达式需要提供函数式接口

调用action.run()时,执行lambda函数的主体

public class LambdaTest {
	public static void main(String []args) {
		repeat(10,()->System.out.println("Hello ~!"));
	}
	public static void repeat(int n,Runnable action) {//此处的Runnable就是一个函数式接口
		for(int i=0;i<n;i++)
			action.run();
	}
}

也可以用构造器引入的方法

调用action.accept(i)方法时,执行lambda函数的主体

public class LambdaTest {
	public static void main(String []args) {
		repeat(10,System.out::println);
		JOptionPane.showMessageDialog(null, "Quit?");
		System.exit(0);
	}

	public static void repeat(int n,IntConsumer action) {
		for(int i=0;i<n;i++)
			action.accept(i+1);
	}
}

以此来输出1-10
在这里插入图片描述

至此,你可以说你已经基本了解lambda表达式啦~~

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值