一、Java8新特性
Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 表达式是一种匿名函数,简单地说,它是没有声明的方法,也即没有访问修饰符、返回值声明和名字。
Lambda 允许把函数作为一个方法的参数(即把lambda表达式作为匿名函数,传递进方法中)。使用 Lambda 表达式可以使代码变的更加简洁紧凑。
语法:
lambda 表达式的语法格式如下:
(parameters) -> expression 或 (parameters) ->{ statements; }
语法:( ) -> { }() : 括号就是接口方法的括号,接口方法如果有参数,也需要写参数。只有一个参数时,括号可以省略。-> : 分割左右部分的,没啥好讲的。{} : 要实现的方法体。只有一行代码时,可以不加括号,可以不写return。
不过看到这里我相信有些小伙伴已经许意识到了,如果接口中有多个方法时,那么按照上面的逻辑lambda表达式恐怕没办法表示了。的确是这样,并非任何接口都支持lambda表达式。
而适用于lambda表达式的接口称之为函数型接口。说白了,函数型接口就是只有一个抽象方法的接口。
二、Lambda 表达式实例
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
public class Java8Tester {
public static void main(String args[]){
Java8Tester tester = new Java8Tester();
// 类型声明
MathOperation addition = (int a, int b) -> a + b;
// 不用类型声明
MathOperation subtraction = (a, b) -> a - b;
// 大括号中的返回语句
MathOperation multiplication = (int a, int b) -> { return a * b; };
// 没有大括号及返回语句
MathOperation division = (int a, int b) -> a / b;
System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
System.out.println("1 + 3 = " + addition.operation(1,3));
System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
System.out.println("10 / 5 = " + tester.operate(10, 5, division));
// 不用括号
GreetingService greetService1 = message ->
System.out.println("Hello " + message);
// 用括号
GreetingService greetService2 = (message) ->
System.out.println("Hello " + message);
greetService1.sayMessage("Runoob");
greetService2.sayMessage("Google");
}
//只包含一个抽象方法的接口,称为函数式接口。以下都是函数式接口
interface MathOperation {
int operation(int a, int b);
}
interface GreetingService {
void sayMessage(String message);
}
//方法
private int operate(int a, int b, MathOperation mathOperation){
return mathOperation.operation(a, b);
}
}
使用 Lambda 表达式需要注意以下两点:
- Lambda 表达式主要用来定义行内执行的方法类型接口,例如,一个简单方法接口。在上面例子中,我们使用各种类型的Lambda表达式来定义MathOperation接口的方法。然后我们定义了sayMessage的执行。
- Lambda 表达式免去了使用匿名方法的麻烦,并且给予Java简单但是强大的函数化的编程能力。
三、什么是函数式接口
Lambda是建立在函数式接口的基础上的。
记住!
(1)只包含一个抽象方法的接口,称为函数式接口。
(2)你可以通过 Lambda 表达式来创建该接口的对象。
(3)我们可以在任意函数式接口上使用 @FunctionalInterface 注解,这样做可以检测它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。
在实际开发者两个比较常见的函数式接口:Runnable接口,Comparator接口
先举例Runnable接口相关
public class LambdaDemo3 {
public static void main(String[] args) {
// 1.1使用匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello world !");
}
}).start();
// 1.2使用 lambda 获得Runnable接口对象
new Thread(() -> System.out.println("Hello world !")).start();
//=============================================================================
// 2.1使用匿名内部类
Runnable race1 = new Runnable() {
@Override
public void run() {
System.out.println("Hello world !");
}
};
// 2.2使用 lambda直接获得接口对象
Runnable race2 = () -> System.out.println("Hello world !");
// 直接调用 run 方法(没开新线程哦!)
race1.run();
race2.run();
}
}
再举一个例子:使用Lambda对数组排序
import java.util.Arrays;
import java.util.Comparator;
public class LambdaDemo4 {
public static void main(String[] args) {
String[] players = {"zhansgan", "lisi", "wangwu", "zhaoliu", "wangmazi"};
// 1.1 使用匿名内部类根据 surname 排序 players
Arrays.sort(players, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return (s1.compareTo(s2));
}
});
// 1.2 使用 lambda 排序,根据 surname
Arrays.sort(players, (String s1, String s2) -> s1.compareTo(s2));
//================================================================================================
// 2.1 使用匿名内部类根据 name lenght 排序 players
Arrays.sort(players, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return (s1.length() - s2.length());
}
});
// 2.2使用Lambda,根据name length
Arrays.sort(players, (String s1, String s2) -> (s1.length() - s2.length()));
//==================================================================================================
// 3.1 使用匿名内部类排序 players, 根据最后一个字母
Arrays.sort(players, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return (s1.charAt(s1.length() - 1) - s2.charAt(s2.length() - 1));
}
});
// 3.2 使用Lambda,根据最后一个字母
Arrays.sort(players, (String s1, String s2) -> (s1.charAt(s1.length() - 1) - s2.charAt(s2.length() - 1)));
}
}
通过上面例子我们再来思考为什么Lambda表达式需要函数式接口?其实很简单目的就是为来保证唯一。
你的Runnable接口只要一个抽象方法,那么我用() -> System.out.println("Hello world !"),就只能代表run方法,如果你下面还有一个抽象方法,那我使用Lambda表达式,那鬼才知道要调用哪个抽象方法呢。
四、方法引用
1、基本介绍
首先注意:方法引用,不是方法调用!
函数式接口的实例可以通过 lambda 表达式、 方法引用、构造方法引用来创建。方法引用是 lambda 表达式的语法糖,任何用方法引用的地方都可由lambda表达式替换,但是并不是所有的lambda表达式都可以用方法引用来替换。
public class TestArray {
public static void main(String[] args) {
List<String> list = Arrays.asList("xuxiaoxiao", "xudada", "xuzhongzhong");
list.forEach(value -> System.out.println(value));
}
}
使用方法引用的方式,和上面的输出是一样的,方法引用使用的是双冒号(::)
list.forEach(System.out::println);
分类:
| 类别 |
使用形式 |
|---|
| 静态方法引用 |
类名 :: 静态方法名 |
| 实例方法引用 |
对象名(引用名) :: 实例方法名 |
| 类方法引用 |
类名 :: 实例方法名 |
| 构造方法引用 |
类名 :: new |
public class Apple {
private String name;
private String color;
private double weight;
int num = 5;
public Apple(String name, String color, double weight) {
this.name = name;
this.color = color;
this.weight = weight;
}
//构造方法
public Apple() {
System.out.println(num);
System.out.println("this is contruction");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
@Override
public String toString() {
return "Apple{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
", weight=" + weight +
'}';
}
//静态方法
public static int compareByWeight(Apple a1, Apple a2) {
double diff = a1.getWeight() - a2.getWeight();
return new Double(diff).intValue();
}
//实例方法
public int compareByWeight2(Apple a1, Apple a2) {
double diff = a1.getWeight() - a2.getWeight();
return new Double(diff).intValue();
}
//类方法(参数传类)
public int compareByWeight3(Apple other) {
//this是当前类的apple,other是传进来的
double diff = this.getWeight() - other.getWeight();
return new Double(diff).intValue();
}
}
import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;
public class LambdaDemo2 {
public LambdaDemo2(){
System.out.println("当前构造方法");
}
public static void main(String[] args) {
//静态方法引用
Apple apple1 = new Apple("红富士", "Red", 280);
Apple apple2 = new Apple("冯心", "Yello", 470);
Apple apple3 = new Apple("大牛", "Red", 320);
Apple apple4 = new Apple("小小", "Green", 300);
List<Apple> appleList = Arrays.asList(apple1, apple2, apple3, apple4);
//lambda 表达式形式
// appleList.sort((Apple a1, Apple a2) -> {
// return new Double(a1.getWeight() - a2.getWeight()).intValue();
// });
//静态方法引用形式(可以看出引用方法比上面的更加简单
appleList.sort(Apple::compareByWeight);
// appleList.forEach(apple -> System.out.println(apple));
//实例方法引用
Apple comparator = new Apple();
appleList.sort(comparator::compareByWeight2);
// appleList.forEach(apple -> System.out.println(apple));
//类方法引用
appleList.sort(Apple::compareByWeight3);
// appleList.forEach(apple -> System.out.println(apple));
//构造方法引用
Supplier<Apple> apple = Apple::new;
//当前类需调用get
Supplier<LambdaDemo2> dangqian = LambdaDemo2::new;
dangqian.get();
}
}
|