Java学习笔记一Lambda表达式

Lambda表达式支持将代码块作为方法参数,Lambda允许使用更简洁的代码来创建只有一个抽象方法的接口(称为函数式接口)的实例。
三部分:形参列表允许省略形参类型,如果形参列表中只有一个参数,甚至连形参列表的圆括号也可省略。箭头,必须通过英文中画线和大于符号组成。代码块,只包含一条语句的话,允许省略代码块的花括号。只有一条return语句,可省略return关键字。

public class CommandTest
{
	public static void main(String[] args)
	{
		ProcessArray pa = new ProcessArray();
		int[] Array = { 3, -4, 6, 4};
		pa.process(array, (int[] target)->{
			int sum = 0;
			for(int tmp: target)
			{
				sum += tmp;
			}
			System.out.println("数组元素总和:"+sum);
		});
	}
}

当使用Lambda表达式代替匿名内部类创建对象时,Lambda表达式的代码块将会代替实现抽象方法的方法体,Lambda表达式就相当于一个匿名方法。

Lambda表达式与匿名内部类主要存在如下区别:

  • 匿名内部类可以为任意接口创建实例-不管接口包含多少个抽象方法,只要匿名内部类实现所有的抽象方法即可;但Lambda表达式只能为函数式接口创建实例。
  • 匿名内部类可以为抽象类甚至普通类创建实例;但Lambda表达式只能为函数式接口创建实例。
  • 匿名内部类实现的抽象方法的方法体允许调用接口中定义的默认方法;但Lambda表达式的代码块不允许调用接口中定义的默认方法。

Lambda表达式与函数式接口

Lambda表达式的类型,也被称为目标类型(target type),Lambda表达式的目标类型必须是"函数式接口(functional interface)"。函数式接口代表只包含一个抽象方法的接口。函数式接口可以包含多个默认方法、类方法,但只能声明一个抽象方法
Java 8专门为函数式接口提供了@FunctionalInterface注解,该注解通常放在接口定义前面,该注解对程序功能没有任何作用,它用于告诉编译器执行更严格检查-检查该接口必须是函数式接口,否则编译器就会报错。

//Runnable接口中只包含一个无参数的方法
//Lambda表达式代表的匿名方法实现了Runnable接口中唯一的、无参数的方法
//下面的Lambda表达式创建了一个Runnable对象
Runnable r = ()->{
	for(int i = 0; i < 100; i++)
		System.out.println();
};

Lambda表达式实现的是匿名方法-因此它只能实现特定函数式接口中的唯一方法。这意味着Lambda表达式有如下限制:Lambda表达式的目标类型必须是明确的函数式接口,Lamdba表达式只能为函数式接口创建对象,Lambda表达式只能实现一个方法,因此它只能为只有一个抽象方法的接口(函数式接口)创建对象。

为了保证Lambda表达式的目标类型是一个明确的函数式接口,可以有如下三种方式:

  • 将Lambda表达式赋给函数式接口类型
  • 将Lambda表达式作为函数式接口类型的参数传给某个方法
  • 使用函数式接口对Lambda表达式进行强制类型转换
//Lambda表达式的目标类型必须是明确的函数式接口
Object obj = ()->{ //出错 不兼容的类型:Object不是函数接口
	for(int i = 0; i < 100; i++)
		System.out.println();
};
//执行强制类型转换,就可以确定表达式的目标类型是明确的函数式接口
Object obj = (Runnable)()->{ 
	for(int i = 0; i < 100; i++)
		System.out.println();
};

Lambda表达式的目标类型完全可能是变化的,但是Lambda表达式实现的匿名方法与目标类型(函数式接口)中唯一的抽象方法有相同的形参列表。

@FunctionalInterface
interface FKTest
{
	void run(); //FKTest接口中的唯一抽象方法不带参数,下面的Lambda表达式也不带参数
}
Object obj = (FKTest)()->{ 
	for(int i = 0; i < 100; i++)
		System.out.println();
};

方法引用与构造器引用

如果Lambda表达式的代码块只有一条代码,可以使用方法引用和构造器引用。

种类 示例 说明 对应的Lambda表达式
引用类方法 类名::类方法 函数式接口中被实现方法的全部参数传给该类方法作为参数 (a,b,…)->类名.类方法(a,b,…)
引用特定对象的实例方法 特定对象::实例方法 函数式接口中被实现方法的全部参数传给该方法作为参数 (a,b,…)->特定对象.实例方法(a,b,…)
引用某类对象的实例方法 类名::实例方法 函数式接口中被实现方法的第一个参数作为调用者,后面的参数全部传给该方法作为参数 (a,b,…)->a.实例方法(b,…)
引用构造器 类名::new 函数式接口中被实现方法的全部参数传给该构造器作为参数 (a,b,…)->new 类名(a,b,…)

引用类方法

@FunctionalInterface
interface Converter
{
	Integer convert(String from); // 抽象方法,将String参数转换为Integer
}

//Lambda表达式创建Converter对象,利用了Integer类中的类方法
Converter converter1 = from->Integer.valueOf(from);
//Converter converter1 = (String from)->{ return Integer.valueOf(from); }
Integer val = converter1.convert("99");
//使用方法引用
Converter converter2 = Integer::valueOf;

引用特定对象的实例方法

//Lambda表达式创建Converter对象
Converter converter1 = from->"fkit.org".indexOf(from);
//Converter converter1 = (String from)->{ return new String("fkit.org").indexOf(from); }
Integer val = converter1.convert("it");  // 值为2
//使用方法引用
Converter converter2 = "fkit.org"::indexOf;

引用某类对象的实例方法

@FunctionalInterface
interface Mytest
{
	String test(String a, int b, int c); // 抽象方法,根据String、int、int三个参数生成String返回值
}
//Lambda表达式创建Mytest对象
Mytest mt1 = (a,b,c)->a.substring(b,c);
//Mytest mt1 = (String a, int b, int c)->{ return a.substring(b,c); }
String str = mt1.test("hello world",0,2);
//使用方法引用
Mytest mt2 = String::substring;

引用构造器

@FunctionalInterface
interface test
{
	JFrame win(String title); // 抽象方法,根据String参数生成JFrame返回值
}
//Lambda表达式创建test对象
test t1 = (String a)->new JFrame(a);
//test t1 = (String a)->{ return new JFrame(a); }
JFrame jf = t1.win("hello world");
//使用方法引用
test t2 = JFrame::new;
发布了134 篇原创文章 · 获赞 141 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/asmartkiller/article/details/104921714
今日推荐