Lambda表达式
一、Lambda表达式简洁
什么是Lambda?
Lambda是JAVA 8添加的一个新特性。说白了,Lambda就是一个匿名函数。
为什么使用Lambda?
使用Lambda表达式可以对一个接口进行非常简单的实现。
Lambda对接口的要求?
虽然可以使用Lambda表达式对某些接口进行简单的实现,但是并不是所有的接口都可以使用Lambda表达式来实现。要求接口中定义的必须要实现的抽象方法只能是一个。
在JAVA8对接口加了一个新的特性:default。
@FunctionalInterface
修饰函数式接口的。接口中的抽象方法只有一个。
代码示例 源码地址
package com.wxk.lambda;
/**
* wxk
*/
public class Program {
public static void main(String[] args) {
// 1.使用接口实现类
Comparator comparator = new MyComparator();
// 2.使用匿名内部类
Comparator comparator1 = new Comparator() {
@Override
public int compare(int a, int b) {
return a - b;
}
};
// 3.使用Lambda表达式来实现接口
Comparator comparator2 = (a, b) -> a - b;
}
}
class MyComparator implements Comparator {
@Override
public int compare(int a, int b) {
return a - b;
}
}
@FunctionalInterface
interface Comparator {
int compare(int a, int b);
}
二、Lambda表达式基础语法
代码示例 源码地址
package com.wxk.lambda.interfaces;
/**
* wxk
*/
@FunctionalInterface
public interface LambdaNoneReturnMultipleParameter {
void test(int a, int b);
}
package com.wxk.lambda.interfaces;
/**
* wxk
*/
@FunctionalInterface
public interface LambdaNoneReturnNoneParameter {
void test();
}
package com.wxk.lambda.interfaces;
/**
* wxk
*/
@FunctionalInterface
public interface LambdaNoneReturnSingleParameter {
void test(int n);
}
package com.wxk.lambda.interfaces;
/**
* wxk
*/
@FunctionalInterface
public interface LambdaSingleReturnMultipleParameter {
int test(int a, int b);
}
package com.wxk.interfaces;
/**
* wxk
*/
@FunctionalInterface
public interface LambdaSingleReturnNoneParameter {
int test();
}
package com.wxk.lambda.interfaces;
/**
* wxk
*/
@FunctionalInterface
public interface LambdaSingleReturnSingleParameter {
int test(int a);
}
package com.wxk.lambda.syntax;
import com.wxk.lambda.interfaces.*;
/**
* wxk
*/
public class Syntax1 {
public static void main(String[] args) {
//1.Lambda表达式的基础语法:
//Lambda是一个匿名函数
//参数列表 方法体
//(): 用来描述参数列表
//->:Lambda运算符,读作 goes to
//{}: 用来描述方法体
//无参无返回
LambdaNoneReturnNoneParameter lambda1 = () -> {
System.out.println("Hello World");
};
lambda1.test();
//无返回值单个参数
LambdaNoneReturnSingleParameter lambda2 = (int a) -> {
System.out.println(a);
};
lambda2.test(10);
//无返回值多个参数
LambdaNoneReturnMultipleParameter lambda3 = (int a, int b) -> {
System.out.println(a + b);
};
lambda3.test(10, 20);
//无参有返回值
LambdaSingleReturnNoneParameter lambda4 = () -> {
System.out.println("lambda4");
return 100;
};
int ret = lambda4.test();
System.out.println(ret);
//一个参数有返回值
LambdaSingleReturnSingleParameter lambda5 = (int a) -> {
System.out.println("lambda5");
return a * 2;
};
int ret2 = lambda5.test(10);
System.out.println(ret2);
//多个参数有返回值
LambdaSingleReturnMultipleParameter lambda6 = (int a, int b) -> {
System.out.println("lambda6");
return a * b;
};
int ret3 = lambda6.test(10, 20);
System.out.println(ret3);
}
}
Hello World
10
30
lambda4
100
lambda5
20
lambda6
200
Process finished with exit code 0
三、Lambda表达式语法精简
代码示例 源码地址
package com.wxk.lambda.syntax;
import com.wxk.lambda.interfaces.LambdaNoneReturnMultipleParameter;
import com.wxk.lambda.interfaces.LambdaNoneReturnSingleParameter;
import com.wxk.lambda.interfaces.LambdaSingleReturnMultipleParameter;
import com.wxk.lambda.interfaces.LambdaSingleReturnNoneParameter;
/**
* wxk
*/
public class Syntax2 {
public static void main(String[] args) {
//语法精简
// 1.参数
// 由于在接口的抽象方法中,已经定义了参数的数量和类型。所以在Lambda表达式中,参数的类型可以省略
//备注:如果需要省略类型,则每一个参数的类型都要省略。千万不要出现一个参数省略,一个参数不省略
LambdaNoneReturnMultipleParameter lambda1 = (a, b) -> {
System.out.println("lambda1 hello world!");
};
lambda1.test(2, 3);
// 2.参数小括号
//如果参数列表中,参数的数量只有一个。此时小括号可以省略
LambdaNoneReturnSingleParameter lambda2 = a -> {
System.out.println("lambda2 hello world!");
};
lambda2.test(2);
// 3.方法大括号
//如果方法体中只有一条语句,此时大括号可以省略
LambdaNoneReturnSingleParameter lambda3 = a -> System.out.println("lambda3 hello world:a=" + a);
lambda3.test(2);
// 4.如果方法体中唯一的一条语句是一个返回语句,则在省略掉大阔号的同事,也不行省略return
LambdaSingleReturnNoneParameter lambda4 = () -> 10;
int ret1 = lambda4.test();
System.out.println("lambda4:ret1=" + ret1);
// 5.类型、方法体、return 关键字都省略了
LambdaSingleReturnMultipleParameter lambda5 = (a, b) -> a + b;
int ret2 = lambda5.test(10, 20);
System.out.println("lambda5:ret2=" + ret2);
}
}
lambda1 hello world!
lambda2 hello world!
lambda3 hello world:a=2
lambda4:ret1=10
lambda5:ret2=30
Process finished with exit code 0
四、Lambda表达式语法进阶之函数引用
代码示例 源码地址
Lambda表达式方法引用
package com.wxk.lambda.syntax;
import com.wxk.lambda.interfaces.LambdaSingleReturnSingleParameter;
/**
* wxk
*/
public class Syntax3 {
public static void main(String[] args) {
// 方法引用:
// 可以快速的讲一个Lambda表达式指向一个已实现的方法
// 语法:方法的隶属者 :: 方法名
LambdaSingleReturnSingleParameter lambda1 = a -> change(a);
int ret1 = lambda1.test(100);
System.out.println("lambda1:ret1=" + ret1);
// 注意:
// 1.参数的数量和类型一定要和接口中定义的方法一致
// 2.返回值的类型一定要和接口中定义的方法一致
// 方法引用:引用了change方法的实现
LambdaSingleReturnSingleParameter lambda2 = Syntax3::change;
int ret2 = lambda2.test(100);
System.out.println("lambda2:ret2=" + ret2);
}
// 方法
private static int change(int a) {
return a * 2;
}
}
lambda1:ret1=200
lambda2:ret2=200
Process finished with exit code 0
Lambda表达式构造方法引用
package com.wxk.lambda.data;
/**
* wxk
*/
public class Person {
public String name;
public int age;
public Person() {
System.out.println("Person类的无参构造方法执行了");
}
public Person(String name, int age) {
this.age = age;
this.name = name;
System.out.println("Person类的有参构造方法执行了");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
package com.wxk.lambda.syntax;
import com.wxk.lambda.data.Person;
/**
* wxk
*/
public class Syntax4 {
public static void main(String[] args) {
PersonCreator creator = () -> new Person();
//构造方法的引用:无参构造函数
PersonCreator creator1 = Person::new;
Person a = creator1.getPerson();
System.out.println("a:" + a.toString());
//构造方法的引用:有参构造函数
PersonCreator2 creator2 = Person::new;
Person b = creator2.getPerson("zhangsan", 18);
System.out.println("b:" + b.toString());
}
}
//需求
interface PersonCreator {
Person getPerson();
}
interface PersonCreator2 {
Person getPerson(String name, int age);
}
Person类的无参构造方法执行了
a:Person{name='null', age=0}
Person类的有参构造方法执行了
b:Person{name='zhangsan', age=18}
Process finished with exit code 0
五、Lambda表达式之综合案例:排序Comparator、Treeset
Comparator排序
代码示例 源码地址
package com.wxk.lambda.exercise;
import com.wxk.lambda.data.Person;
import java.util.ArrayList;
/**
* wxk
*/
public class Exercise1 {
public static void main(String[] args) {
ArrayList<Person> list = new ArrayList<>();
list.add(new Person("xiaoming", 10));
list.add(new Person("lilei", 11));
list.add(new Person("hanmeimei", 12));
list.add(new Person("lily", 9));
list.add(new Person("lucy", 9));
list.add(new Person("polly", 3));
list.add(new Person("uncle wang", 40));
//排序
list.sort((o1, o2) -> o2.age - o1.age);
System.out.println("年龄降序排序:" + list);
}
}
Person类的有参构造方法执行了
Person类的有参构造方法执行了
Person类的有参构造方法执行了
Person类的有参构造方法执行了
Person类的有参构造方法执行了
Person类的有参构造方法执行了
Person类的有参构造方法执行了
年龄降序排序:[Person{name='uncle wang', age=40}, Person{name='hanmeimei', age=12}, Person{name='lilei', age=11}, Person{name='xiaoming', age=10}, Person{name='lily', age=9}, Person{name='lucy', age=9}, Person{name='polly', age=3}]
Process finished with exit code 0
Treeset排序
异常示例 源码地址
package com.wxk.lambda.exercise;
import com.wxk.lambda.data.Person;
import java.util.TreeSet;
/**
* wxk
*/
public class Exercise2 {
public static void main(String[] args) {
//Treeset
TreeSet<Person> set = new TreeSet<>();
set.add(new Person("xiaoming", 10));
set.add(new Person("lilei", 11));
set.add(new Person("hanmeimei", 12));
set.add(new Person("lily", 9));
set.add(new Person("lucy", 9));
set.add(new Person("polly", 3));
set.add(new Person("uncle wang", 40));
System.out.println(set);
}
}
Person类的有参构造方法执行了
Exception in thread "main" java.lang.ClassCastException: com.wxk.lambda.data.Person cannot be cast to java.lang.Comparable
at java.util.TreeMap.compare(TreeMap.java:1290)
at java.util.TreeMap.put(TreeMap.java:538)
at java.util.TreeSet.add(TreeSet.java:255)
at com.wxk.lambda.exercise.Exercise2.main(Exercise2.java:17)
Process finished with exit code 1
代码示例1 源码地址
相减返回0会去重
package com.wxk.lambda.exercise;
import com.wxk.lambda.data.Person;
import java.util.TreeSet;
/**
* wxk
*/
public class Exercise2 {
public static void main(String[] args) {
//Treeset
//使用Lambda表达式来实现Comparator接口,并实例化一个Treeset对象 会去重
TreeSet<Person> set = new TreeSet<>((o1, o2) -> o2.age - o1.age);
set.add(new Person("xiaoming", 10));
set.add(new Person("lilei", 11));
set.add(new Person("hanmeimei", 12));
set.add(new Person("lily", 9));
set.add(new Person("lucy", 9));
set.add(new Person("polly", 3));
set.add(new Person("uncle wang", 40));
System.out.println(set);
}
}
Person类的有参构造方法执行了
Person类的有参构造方法执行了
Person类的有参构造方法执行了
Person类的有参构造方法执行了
Person类的有参构造方法执行了
Person类的有参构造方法执行了
Person类的有参构造方法执行了
[Person{name='uncle wang', age=40}, Person{name='hanmeimei', age=12}, Person{name='lilei', age=11}, Person{name='xiaoming', age=10}, Person{name='lily', age=9}, Person{name='polly', age=3}]
Process finished with exit code 0
*代码示例2 源码地址
package com.wxk.lambda.exercise;
import com.wxk.lambda.data.Person;
import java.util.TreeSet;
/**
* wxk
*/
public class Exercise2 {
public static void main(String[] args) {
//Treeset
//使用Lambda表达式来实现Comparator接口,并实例化一个Treeset对象
TreeSet<Person> set = new TreeSet<>((o1, o2) -> (o2.age >= o1.age) ? -1 : 1);
set.add(new Person("xiaoming", 10));
set.add(new Person("lilei", 11));
set.add(new Person("hanmeimei", 12));
set.add(new Person("lily", 9));
set.add(new Person("lucy", 9));
set.add(new Person("polly", 3));
set.add(new Person("uncle wang", 40));
System.out.println(set);
}
}
Person类的有参构造方法执行了
Person类的有参构造方法执行了
Person类的有参构造方法执行了
Person类的有参构造方法执行了
Person类的有参构造方法执行了
Person类的有参构造方法执行了
Person类的有参构造方法执行了
[Person{name='polly', age=3}, Person{name='lucy', age=9}, Person{name='lily', age=9}, Person{name='xiaoming', age=10}, Person{name='lilei', age=11}, Person{name='hanmeimei', age=12}, Person{name='uncle wang', age=40}]
Process finished with exit code 0
六、Lambda表达式之综合案例:forEach()
package com.wxk.lambda.exercise;
import java.util.ArrayList;
import java.util.Collections;
/**
* wxk
*/
public class Exercise3 {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
//将集合中的每一个元素都带入到方法accept中
//list.forEach(System.out::println);
//输出集合中的所有偶数
list.forEach(ele -> {
if (ele % 2 == 0) {
System.out.println(ele);
}
});
}
}
2
4
6
8
0
Process finished with exit code 0
七、Lambda表达式之综合案例:removeIf()
package com.wxk.lambda.exercise;
import com.wxk.lambda.data.Person;
import java.util.ArrayList;
import java.util.ListIterator;
/**
* wxk
*/
public class Exercise4 {
public static void main(String[] args) {
//需求:删除集合中满足条件的元素
ArrayList<Person> list = new ArrayList<>();
list.add(new Person("xiaoming", 10));
list.add(new Person("lilei", 11));
list.add(new Person("hanmeimei", 12));
list.add(new Person("lily", 9));
list.add(new Person("lucy", 9));
list.add(new Person("polly", 3));
list.add(new Person("uncle wang", 40));
//方法一:迭代器
// ListIterator<Person> it = list.listIterator();
//
// while (it.hasNext()) {
// Person p = it.next();
// if (p.age > 10) {
// it.remove();
// }
// }
//
// System.out.println(list);
//Lambda实现
//将集合中的每一个元素都带入到test方法中,如果返回值是ture,则删除这个元素
list.removeIf(ele -> ele.age > 10);
System.out.println(list);
}
}
Person类的有参构造方法执行了
Person类的有参构造方法执行了
Person类的有参构造方法执行了
Person类的有参构造方法执行了
Person类的有参构造方法执行了
Person类的有参构造方法执行了
Person类的有参构造方法执行了
[Person{name='xiaoming', age=10}, Person{name='lily', age=9}, Person{name='lucy', age=9}, Person{name='polly', age=3}]
Process finished with exit code 0
八、Lambda表达式之综合案例:线程实例化
package com.wxk.lambda.exercise;
/**
* wxk
*/
public class Execise5 {
public static void main(String[] args) {
//需求:开辟一条线程,做一个数字的输出
Thread t = new Thread(() -> {
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
});
t.start();
}
}
0
1
2
...
99
Process finished with exit code 0
九、系统内置函数式接口
java.util.function.*
BiConsumer
BiFunction
BinaryOperator
BiPredicate
BooleanSupplier
Consumer
DoubleBinaryOperator
DoubleConsumer
DoubleFunction
DoublePredicate
DoubleSupplier
DoubleToIntFunction
DoubleToLongFunction
DoubleUnaryOperator
Function
IntBinaryOperator
IntConsumer
IntFunction
IntPredicate
IntSupplier
IntToDoubleFunction
IntToLongFunction
IntUnaryOperator
LongBinaryOperator
LongConsumer
LongFunction
LongPredicate
LongSupplier
LongToDoubleFunction
LongToIntFunction
LongUnaryOperator
ObjDoubleConsumer
ObjIntConsumer
ObjLongConsumer
Predicate
Supplier
ToDoubleBiFunction
ToDoubleFunction
ToIntBiFunction
ToIntFunction
ToLongBiFunction
ToLongFunction
UnaryOperator
package com.wxk.lambda.functional;
import java.util.function.*;
/**
* wxk
*/
public class FunctionalInterface {
public static void main(String[] args) {
//系统内置的一些函数式接口
// Predicate<T> :参数T 返回值 boolean
// IntPredicate int -> boolean
// ...
// Consumer<T> :参数T 返回值 void
// IntConsumer int -> void
// ...
// Function<T,R> :参数T 返回值 R
// IntFunction<R> int -> R
// IntToLongFunction int -> Ling
// ...
// Supplier<T> :参数无 返回值 T
// UnaryOperator<T> :参数T 返回值 T
// BinaryOperator<T> :参数T,T 返回值 T
// BiFunction<T,U,R> :参数T,U 返回值 R
// BiPredicate<T,U> :参数T,U 返回值 boolean
// BiConsumer<T,U> :参数T,U 返回值 void
}
}
十、闭包问题
提升变量的生命周期,获取方法的局部变量
package com.wxk.lambda.closure;
import java.util.function.Supplier;
/**
* wxk
*/
public class ClosureDemo {
public static void main(String[] args) {
int n = getNumber().get();
System.out.println(n);
}
private static Supplier<Integer> getNumber() {
int num = 10;
return () -> num;
}
}
10
Process finished with exit code 0
在闭包中引用的变量一定是常量