概念说明
- Lambda表达式是Java8提供的新特性,支持将代码块作为方法的参数。
- Lambda表达式支持使用简洁的代码创建只有一个方法的接口(函数式接口)。
- 只包含一个方法的接口也称为函数式接口。
Lambda表达式示例
在命令模式的例子中(地址:http://www.cnblogs.com/rask/p/8309876.html),可以直接向业务处理类方法传入实际代码,有两种实现方式:局部匿名内部类和Lambda表达式。
public class Test { public static void main(String[] args) { DataProcess dp = new DataProcess(); int[] data = { 1, 2, -10, 9, 18 }; // 使用局部内部类 dp.service(data, new ICommand() { @Override public void process(int[] data) { System.out.print("数组data中的元素有:"); for (int item : data) { System.out.print(item + " "); } } }); // 使用lambda表达式 dp.service(data, target -> { int sum = 0; for (int i = 0; i < target.length; i++) { sum += data[i]; } System.out.println("数组所有元素之和为:" + sum); }); } }
Lambda表达式的主要作用:用于替换匿名内部类繁琐的语法。
Lambda表达式语法格式
(参数类型 参数1,参数类型,参数2)->{代码块}
- 形参列表:允许省略形参参数类型。如果只有一个参数,圆括号也可以省略。
- “->” :使用英文的中画线和大于号表示。
- 代码块:如果代码块只有一条语句,可以省略"{}"。如果代码块只有一条return语句,return关键字也可以省略。
示例代码:
package com.etc.qs; /**函数式接口*/ @FunctionalInterface interface OneAble { void method(); } /**函数式接口*/ @FunctionalInterface interface TwoAble { void method(String str); } /**函数式接口*/ @FunctionalInterface interface ThreeAble { int method(int a, int b); } public class QSDemo { public void OneAbleImpl(OneAble oneAble) { System.out.println(oneAble.toString()); oneAble.method(); } public void TwoAbleImpl(TwoAble twoAble) { System.out.println(twoAble.toString()); twoAble.method("Hello Lamda!"); } public void ThreeAbleImpl(ThreeAble threeAble) { System.out.println("10和15的和为:" + threeAble.method(10, 15)); } public static void main(String[] args) { QSDemo q = new QSDemo(); // Lambda表达式代码块只有一条语句,可以省略"{}" q.OneAbleImpl(() -> System.out.println("新年好!")); // Lambda表达式的形参列表只有一个形参,可以省略"()" q.TwoAbleImpl(str -> { System.out.println(str); System.out.println("执行了一个参数的方法!"); }); // Lambda表达式代码块只有一条语句,可以省略"{}",如果该条语句为带返回值,同时可以省略return关键字 q.ThreeAbleImpl((a, b) -> a + b); } }
函数式接口
Lambda表达式的类型,也称为“目标类型”。Lambda表达式的目标类型必须是“函数式”接口(functional interface)。
函数式接口:只有一个抽象方法的接口。这种类型的接口也称为SAM接口,即Single Abstract Method interfaces。
Java8提供了函数式接口注解:
@FunctionalInterface
该注解用于编译时检查接口是否满足函数式接口规范。
总而言之,Lambda表达式使用限制归纳为以下两点:
- Lambda表达式目标类型必须是函数式接口。
- Lambda只能为函数式接口创建对象。
Lambda表达式方法引用和构造器引用
如果Lambda表达式代码块只有一条语句,可以在代码中使用方法引用和构造器引用,使用”::”进行引用。
引用方式汇总:
种类 | 引用示例 | 说明 | 对应Lambda表达式 |
引用类方法 | 类名::类方法 | 函数式接口中被实现方法的全部参数传给该类方法作为参数 | (a,b,...)->类名.类方法(a,b,...) |
引用特定对象的实例方法 | 特定对象::实例方法 | 函数式接口中被实现方法的全部参数传给该方法作为参数 | (a,b,...)->特定对象.实例方法(a,b,...) |
引用某类对象的实例方法 | 类名::实例方法 | 函数式接口中被实现方法的第一个参数作为调用者,后面的参数全部传给该方法作为参数 | (a,b,...)->a.实例方法(b,...) |
引用构造器 | 类名::new | 函数式接口中被实现方法的全部参数传给该构造器作为参数 | (a,b,...)->new 类名(a,b,...) |
表格数据来源:《疯狂java讲义》
引用类方法示例代码:
/**
* 函数式接口
* 用于把字符串转换为整数
*
*/
@FunctionalInterface
interface Converter{
Integer convert(String from);
}
public class MethodRef {
public static void main(String[] args) {
//Converter converter=(String from)->{return Integer.valueOf(from);};
Converter converter=Integer::valueOf;//引用类方法valueOf
Integer val=converter.convert("8899");
System.out.println(val);
}
}
引用特定对象的实例方法示例代码:
/**
* 函数式接口1
* 判断字符串中是否包含指定字符
*
*/
@FunctionalInterface
interface Converter1{
int convert(String from);
}
public class MethodRef {
public static void main(String[] args) {
Converter1 converter1="etc.com"::indexOf;//indexOf为String类的实例方法
int result=converter1.convert("c");
System.out.println(result);
}
}
引用某类对象的实例方法示例代码:
/**
* 函数式接口2
* 字符串截取
*
*/
@FunctionalInterface
interface Converter2{
String convert(String from,int a,int b);
}
public class MethodRef {
public static void main(String[] args) {
Converter2 converter2=String::substring;//引用String类的实例方法
String result=converter2.convert("etc.com",2,4);
System.out.println(result);
}
}
引用构造器示例代码:
/**打开一个Frame窗体*/
@FunctionalInterface
interface MyFrame {
JFrame windows(String title);
}
public class MethodRef {
public static void main(String[] args) {
MyFrame mf=JFrame::new;//引用JFrame类的构造器
JFrame jf=mf.windows("我的窗体");
jf.setVisible(true);
jf.setSize(400, 400);
}
}