Lambda简介
1.1 什么是Lambda?
- Lambda是JAVA 8添加的一个新特性。Lambda就是一个匿名函数
1.2 为什么要使用Lambda?
- 使用Lambda表达式可以对一个接口进行非常简介的实现。
1.3 Lambda对接口的要求?
- 要求接口中定义的必须要实现的抽象方法只能是一个
在JAVA8中对接口加了一个新特性:default
可以使用default对接口方法进行修饰,被修饰的方法在接口中有一个默认实现。这样的方法实现类可以实现,也可以不实现。所以default修饰的方法对Lambda没有影响。
1.4 @FunctionalInterface
- 修饰函数式接口,接口中的抽象方法只有一个。
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基础语法
2.1 准备工作 创建6个接口
2.2 Lambda表达式基本语法
public static void main(String[] args) {
// 1.Lambda表达式的基础语法:
// 函数:返回值类型 方法名 参数列表 方法体
// Lambda是一个匿名函数,关注参数列表和方法体
// ( ):用来描述参数列表
// { }:用来描述方法体
// -> :Lambda运算符,读作goes to
// 1.1.无参无返回
LambdaNoneReturnNoneParameter lambda1 = () -> {
System.out.println("hello world");
};
lambda1.test(); //hello world
// 1.2.无返回值、单个参数
LambdaNoneReturnSingleParameter lambda2 = (int a)->{
System.out.println(a);
};
lambda2.test(10); //10
// 1.3.无返回值、多个参数
LambdaNoneReturnMutipleParemeter lambda3 = (int a,int b)->{
System.out.println(a+b);
};
lambda3.test(10,20); //30
// 2.1.无参、有返回值
LambdaSingleReturnNoneParameter lambda4 = ()->{
System.out.print("lambda4 ");
return 100;
};
int ret = lambda4.test();
System.out.println(ret); //lambda4 100
// 2.2.有返回值、单个参数
LambdaSingleReturnSingleParameter lambda5 = (int a)->{
return a*2;
};
int ret2 = lambda5.test(10);
System.out.println(ret2); //20
// 2.3.有返回值、多个参数
LambdaSingleReturnMutipleParameter lambda6 = (int a,int b)->{
return a+b;
};
int ret3 = lambda6.test(20, 30);
System.out.println(ret3); //50
}
Lambda语法精简
public static void main(String[] args) {
// 语法精简:
// 1.参数类型:
// 由于在接口的抽象方法中,已经定义了参数的数量和类型。
// 所以在Lambda表达式中,参数类型可以省略
// 备注:如果需要省略类型,则每一个参数类型都要省略。千万不要出现有的省略,有的不省略。
LambdaNoneReturnMutipleParemeter lambda1 = (a, b) -> {
System.out.println("hello world");
};
// 2.参数小括号
// 如果参数列表中,参数的数量只有一个。此时小括号可以省略
LambdaNoneReturnSingleParameter lambda2 = a -> {
System.out.println("hello world");
};
// 3.方法大括号
// 如果方法体只有一条语句,此时大括号可以省略
LambdaNoneReturnSingleParameter lambda3 = a -> System.out.println("hello world");
// 4.如果方法体中唯一的一条语句是一个返回语句,则在省略大括号的同时,也必须省略掉return
LambdaSingleReturnNoneParameter lambda4 = () -> 10;
// 精简前:
LambdaSingleReturnMutipleParameter lambda5 = (int a,int b)->{
return a+b;
};
// 精简后:
LambdaSingleReturnMutipleParameter lambda6 = (a, b) -> a + b;
}
Lambda语法进阶
4.1.方法引用
public static void main(String[] args) {
// 方法引用:
// 可以快速的将一个Lambda表达式的实现只想一个已经实现的方法。
// 语法:方法的隶属者::方法名
// 注意:
// 1.参数数量和类型一定要和接口中定义的方法一致
// 2.返回值的类型页一定要和接口中定义的方法一致
LambdaSingleReturnSingleParameter lambda1 = a -> change(a);
// 方法引用:引用了change方法的实现。
LambdaSingleReturnSingleParameter lambda2 = Syntax3::change;
}
private static int change(int a) {
return a * 2;
}
4.2.构造方法引用
public class Syntax4 {
public static void main(String[] args) {
PersonCreater creater = ()->new Person();
// 构造方法的引用:
// 无参构造方法引用
PersonCreater creater1 = Person::new;
Person person = creater1.getPerson();
// 有参构造方法引用
PersonCreater2 creater2 = Person::new;
Person person1 = creater2.getPerson("zhangsan",10);
}
}
// 原始写法
class PersonDemo implements PersonCreater{
@Override
public Person getPerson() {
return new Person();
}
}
// 需求:
interface PersonCreater{
// 无参方法
Person getPerson();
}
interface PersonCreater2{
// 有参方法
Person getPerson(String name,int age);
}
Lambda综合案例
5.1.案例一:Lambda实现Comparator接口进行ArrayList集合排序
public class Exercise1 {
// 集合排序:
// ArrayList<>
public static void main(String[] args) {
// 需求:已知在一个ArrayList中有若干个Person对象,
// 将这些Person对象按年龄进行降序排序
ArrayList<Person> list = new ArrayList<>();
list.add(new Person("cc", 10));
list.add(new Person("zz", 17));
list.add(new Person("jj", 20));
list.add(new Person("bb", 33));
list.add(new Person("mm", 19));
list.add(new Person("ww", 12));
list.add(new Person("uu", 40));
// Comparator接口
// @FunctionalInterface
// public interface Comparator<T> {
// int compare(T o1, T o2);
// }
// 实现:
list.sort((o1, o2) -> o2.age - o1.age);
}
}
5.2.案例二:Lambda实现Comparator接口进行TreeSet集合排序
public class Exercise2 {
public static void main(String[] args) {
// TreeSet
// TreeSet带参构造方法,需要实现Comparator接口
// public TreeSet(Comparator<? super E> comparator) {
// this(new TreeMap<>(comparator));
// }
// 使用Lambda表达式来实现Comparator接口,并实例化一个TreeSet对象
TreeSet<Person> set = new TreeSet<>((o1,o2)->{
if (o1.age >= o2.age){
return -1;
}else {
return 1;
}
});
set.add(new Person("cc", 10));
set.add(new Person("zz", 17));
set.add(new Person("jj", 20));
set.add(new Person("bb", 33));
set.add(new Person("mm", 19));
set.add(new Person("ww", 12));
set.add(new Person("vv", 12));
set.add(new Person("uu", 40));
System.out.println(set);
}
}
5.3.案例三:Lambda实现Consumer接口进行集合遍历
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);
// 集合遍历
// @FunctionalInterface
// public interface Consumer<T> {
// void accept(T t);
// }
// 将集合中的每一个元素都带入到方法accept中。
// list.forEach(System.out::println);
// 输出集合中所以的偶数
list.forEach(ele ->{
if (ele %2 ==0){
System.out.println(ele);
}
});
}
}
5.4.案例四:Lambda实现Predicate接口根据条件删除集合元素
public class Exercise4 {
public static void main(String[] args) {
// 需求:删除集合中满足条件的元素
ArrayList<Person> list = new ArrayList<>();
list.add(new Person("cc", 10));
list.add(new Person("zz", 17));
list.add(new Person("jj", 20));
list.add(new Person("bb", 33));
list.add(new Person("mm", 19));
list.add(new Person("ww", 12));
list.add(new Person("uu", 40));
// 题目:删除集合中年龄>30的元素
// 原始写法
ListIterator<Person> iterator = list.listIterator();
while (iterator.hasNext()){
Person ele = iterator.next();
if (ele.age>30){
iterator.remove();
}
}
// 将集合每一个元素都带入到test方法中,如果返回值是true,则删除这个元素
// @FunctionalInterface
// public interface Predicate<T> {
// boolean test(T t);
// }
// Lambda实现
list.removeIf(ele->ele.age>30);
}
}
5.5.案例五:Lambda实现Runnable接口
public class Exercise5 {
public static void main(String[] args) {
// 需求:开辟一条线程。做一个数字的输出。
// @FunctionalInterface
// public interface Runnable {
// public abstract void run();
// }
Thread t = new Thread(()->{
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
});
t.start();
}
}
系统内置函数式接口
// 系统内置的一些函数式接口
Predicate<T>{ boolean test(T t);} :参数T 返回值boolean
Consumer<T> { void accept(T t);} :参数T 返回值void
Function<T, R> { R apply(T t);} :参数T 返回值R
BiPredicate<T, U> {boolean test(T t, U u);} :参数T,U 返回值boolean
BiConsumer<T, U> {void accept(T t, U u);} :参数T,U 返回值void
BiFunction<T, U, R> { R apply(T t, U u);} :参数T,U 返回值R
Supplier<T> { T get();} :无参 返回值T
UnaryOperator<T> extends Function<T, T> { } :参数T 返回值T
BinaryOperator<T> extends BiFunction<T,T,T> {} :参数T,T 返回值T
闭包问题
7.1.闭包问题
- Lambda表达式实现接口的方法时,如果使用到局部变量,则会默认将其添加一个fianl属性,使其变成常量,并提升生命周期
闭包中引用的一定是常亮,如果不是,系统会自动添加fianl属性,使其变成常亮
public class ClosureDemo {
public static void main(String[] args) {
Integer i = getNumber().get();
System.out.println(i); // 10
// 因为闭包,提升了num局部变量的声明周期,输出仍然为num的值
}
// 闭包情况
private static Supplier<Integer> getNumber(){
int num = 10;
return ()->num; // 闭包
}
}
public class ClosureDemo2 {
public static void main(String[] args) {
int a = 10; // a为局部变量
Consumer<Integer> c = ele->{
System.out.println(a); // 闭包情况,a变成常量
};
// 因为a变量在闭包中,变为了常亮,所以不可以进行运算和赋值操作
// 所以闭包中a报错 Variable used in lambda expession should be final or fectively fnal
a++;
c.accept(1);
}
}