文章目录
Lambda表达式简介
什么是Lambda表达式
Lambda表达式是Java8的一个新特性。说白了,Lambda就是一个匿名函数。
为什么要使用Lambda
之前我们是如何实现一个接口的???
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表达式可以对一个接口进行非常简洁的实现。说白了,Lambda表达式就是实现接口用的。
Lambda对接口的要求
虽然我们可以使用Lambda表达式对某些接口进行简单的实现,但并不是所有的接口都可以用Lambda表达式来实现。要求接口中定义的必须要实现的抽象方法只能有一个(default方法不算入其中)
在Java8对接口加了一个新特性:default
@FunctionalInterFace
修饰函数式接口,函数式接口也就是该接口内只有一个必须要实现的抽象方法。
基础语法
前面提到,Lambda表达式实际上就是一个匿名函数,函数包括:
- 返回值类型
- 方法名
- 参数列表
- 方法体
匿名函数自然就没有方法名,而且Lambda表达式也不需要返回值类型(可以从接口里面的那一个抽象方法推断出来),所以提供给Lambda表达式参数列表和方法体就够了。
Lambda的基础语法:
//():用于描述参数列表
// {}:用来描述方法体
// ->:Lambda运算符
//无参无返回
LambdaNoneReturnNoneParameter lambda1 = () -> {
System.out.println("hello world");
};
lambda1.test();
//单个参数 无返回值
LambdaNoneReturnSingleParameter lambda2 = (int a) -> {
System.out.println(a);
};
lambda2.test(10);
//多个参数 无返回值
LambdaNoneReturnMutipleParameter lambda3 = (int a, int b) -> {
System.out.println(a + " " + b);
};
lambda3.test(100, 200);
//有返回值 无参数
LambdaSingleReturnNoneParameter lambda4 = () -> {
System.out.println("sdas");
return 100;
};
int test = lambda4.test();
System.out.println(test);
//有返回值 有参数
LambdaSingleReturnSingleParameter lambda5 = (int a) -> {
return 10 * a;
};
int test1 = lambda5.test(12);
System.out.println(test1);
}
语法精简
//语法精简
//1.参数:
//在Lambda表达式中,参数的类型可以省略
//如果要省略的话所有参数都要省略
LambdaNoneReturnMutipleParameter lambda1 = (a, b) -> {
System.out.println(a + b);
};
lambda1.test(10, 20);
//2.参数小括号
//如果参数列表中中参数的数量只有一个,此时小括号可以省略
LambdaNoneReturnSingleParameter lambda2 = a -> {
System.out.println("hello world");
};
//3.方法大括号
//如果方法中只有一条语句,大括号可以省略
//类似与if for语句
LambdaNoneReturnSingleParameter lambda3 = a -> System.out.println("hello world");
//4.如果方法体中唯一一个语句是返回语句,则在省略大括号的同时也要省略掉return语句
LambdaSingleReturnNoneParameter lambda4 = () -> 10;
//综合练习
LambdaSingleReturnMutipleParameter lambda5 = (a, b) -> a + b;
int test = lambda5.test(55, 5);
System.out.println(test);
语法进阶(方法引用)
public class Syntax3 {
public static void main(String[] args) {
//方法引用
//可以快速的将一个Lambda表达式的实现指向一个已经实现的方法
//语法: 方法的隶属者::方法名
//静态方法: 类名::方法名
//非静态方法: this::方法名
LambdaSingleReturnSingleParameter lambda1 = a -> change(a);
LambdaSingleReturnSingleParameter lambda2=Syntax3::change;
}
private static int change(int a) {
return a * 2;
}
}
构造函数的方法引用
public class Syntax4 {
public static void main(String[] args) {
PersonCreater creater=()->new Person();
//构造方法的方法引用:
PersonCreater creater1=Person::new;
creater1.getPerson();
//倘如想要调用其有参的构造方法
PersonCreater2 creater2=Person::new;
Person person = creater2.getPerson("lzh",20);
}
}
interface PersonCreater{
Person getPerson();
}
interface PersonCreater2{
Person getPerson(String name,int age);
}
无论有参 无参的构造函数,写法都是Person::new
,调用哪个构造方法是由接口里面的方法决定的。
综合案例
ArrayList排序
Java8为List接口新增了sort(Comparator c)
和replaceAll()
方法。Comparator
接口是一个函数式接口。
public class Exercise1 {
public static void main(String[] args) {
//需求:在一个ArrayList中有若干个Person对象。将其按年龄降序排序
ArrayList<Person> list = new ArrayList<Person>();
list.add(new Person("小明", 12));
list.add(new Person("lilei", 10));
list.add(new Person("lili", 10));
list.add(new Person("miaomiao", 30));
list.add(new Person("lzh", 80));
list.add(new Person("ll", 18));
list.add(new Person("hh", 40));
list.add(new Person("ww", 1));
list.sort((o1, o2) -> o1.age - o2.age);
// Collections.sort();
// Arrays.sort();
System.out.println(list);
//利用流式编程试一下
list.stream().sorted((o1,o2)->o1.age-o2.age).forEach(System.out::println);
}
}
不用实现比较接口向TreeSet插入数据
插入到TreeSet集合中的元素一般都要实现Comparable
接口。
如果没有实现:
可以在初始化TreeSet
的时候传入一个比较器,这样元素就不需要再实现Comparable
接口了。
public class Exercise2 {
public static void main(String[] args) {
//TreeSet<Person> set=new TreeSet<>();
//TreeSet<Person> set=new TreeSet<>(((o1, o2) -> o1.age- o2.age));
//set的去重规则
TreeSet<Person> set = new TreeSet<>(((o1, o2) -> {
if (o1.age >= o2.age) {
return -1;
} else {
return 1;
}
}));
set.add(new Person("小明", 12));
set.add(new Person("lilei", 10));
set.add(new Person("lili", 10));
set.add(new Person("miaomiao", 30));
set.add(new Person("lzh", 80));
set.add(new Person("ll", 18));
set.add(new Person("hh", 40));
set.add(new Person("ww", 1));
System.out.println(set);
}
}
遍历List
Collections.addAll()
是个好东西;- 使用
Iterable
接口中的forEach()
来遍历集合很方便,相比于迭代器;
public class Exercise3 {
public static void main(String[] args) {
//集合的遍历
ArrayList<Integer> list = new ArrayList<>();
//便捷的增加元素
Collections.addAll(list, 1, 2, 3, 4, 5, 67, 8, 9);
//将集合中的每一个元素都带入Consumer中的accept()
//list.forEach(System.out::println);
//加些自己的逻辑
list.forEach(ele -> {
if (ele % 2 == 0) {
System.out.println(ele);
}
});
}
}
删除集合中的某些满足条件的元素
removeIf()
是Collection
接口里面的方法。
public class Exercise4 {
public static void main(String[] args) {
//需求:删除集合中满足条件的集合
ArrayList<Person> list = new ArrayList<Person>();
list.add(new Person("小明", 12));
list.add(new Person("lilei", 10));
list.add(new Person("lili", 10));
list.add(new Person("miaomiao", 30));
list.add(new Person("lzh", 80));
list.add(new Person("ll", 18));
list.add(new Person("hh", 40));
list.add(new Person("ww", 1));
//删除集合中年龄>20岁的元素
//使用迭代器实现
/* ListIterator<Person> iterator = list.listIterator();
while (iterator.hasNext()) {
Person next = iterator.next();
if (next.age > 20) {
iterator.remove();
}
}
System.out.println(list);*/
//将集合中的每一个元素都带入到Predicate中的test方法中 如果返回true 就删除
list.removeIf(ele -> ele.age > 20);
System.out.println(list);
}
}
快速的创建线程实例
Runnable
也是一个函数式接口,可以使用Lambda表达式实现。
public class Exercise5 {
public static void main(String[] args) {
//需求:开辟一个线程
//Runnable接口是一个函数式接口
Thread thread = new Thread(() -> {
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
});
thread.start();
}
}
闭包
如果我们要在Lambda中使用局部变量,那么这个局部变量必须为常量
小结
- Lambda表达式是Java8新增的特性,可以非常简单的实现函数式接口;
- Lambda表达式的基础语法:()->{} 参数列表 Lambda关键字 方法体;
- 语法简化:可以省去参数的类型;
- 当参数只有一个时,可以省去参数列表的小括号;
- 当方法体内的语句只有一行时,可以省去方法体的大括号;
- 当方法体内的语句只有一行且为return时,可以省去大括号和return关键字;
- 方法引用与构造方法引用;
- 实例:list.sort()排序 向TreeSet中插入元素 list.removeIf()删除元素 list.forEach()遍历 实例化线程;
- Lambda中使用到的局部变量一定是常量;