1. Lambda表达式
1. 学习内容
- Lambda表达式概述
- Lambda表达式语法
- Lambda表达式使用
- Stream流概述
- Stream流基本使用
2. 学习目标
- Lambda表达式概述–>理解
- Lambda表达式语法–>重点掌握
- Lambda表达式使用–>重点掌握
- Stream流概述–>理解
- Stream流基本使用–>重点掌握
3. 学习笔记
1. Lambda表达式–>重点掌握
1. Lambda表达式概述
Lambda表达式是在JDK1.8后新增特性,主要的目的是用于取代匿名内部类(简化匿名内部类),使用条件就是借口,且必须是函数式接口@FunctionalInterface
注解的接口,出现的目的为了简化Java开发代码,让程序更加健壮,代码更加优雅,尤其是在操作集合的时候非常非常的简便,但是如果不熟悉则阅读非常类
Java官方也对Lambda表达式提供了很多的接口供开发人员使用,只要是Java提供的都是使用@FunctionalInterface
注解的接口,只要用此注解的接口都是为了Lambda表达式使用的,但是不包含抽象类,只适用于接口
2. @FunctionalInterface函数式接口注解–>重点掌握
@FunctionalInterface此注解仅用于在接口中使用,并且主要作用就是限制接口中的抽象方法数量(数量必须是一个),但是不限制default
和static
修饰的带有方法体的方法,使用函数式接口主要用于Lambda表达式语法调用
函数式接口代码案例
/**
* 函数式接口
*/
@FunctionalInterface
public interface FunctionInterface {
// 只允许有一个抽象方法
void func();
// 如果出现第二个抽象方法则报错
// void func01();
// 但是允许default和static修饰的方法
default void method01() {
System.out.println("带有方法体的default修饰的方法...");
}
// 但是允许default和static修饰的方法
static void method02() {
System.out.println("带有方法体的static修饰的方法...");
}
}
3. Lambda表达式代码案例–>重点掌握
1. Lambda表达式语法格式–>重点掌握
Lambda表达式语法格式:()->{}
()
:用于表示方法形参,仅用于声明形参,但不是传至->
:Lambda表达式的运算符,一般读作goes to
{}
:Lambda表达式方法体,用于编写逻辑代码,抽象方法的具体实现
2. 函数式接口定义–>仅用于Lambda表达式测试使用
/**
* 函数式接口定义
*/
/**
* 无参无返回值接口
*/
@FunctionalInterface
interface FunctionInterface1 {
void func();
}
/**
* 单参无返回值接口
*/
@FunctionalInterface
interface FunctionInterface2 {
void func(String param);
}
/**
* 无参有返回值接口
*/
@FunctionalInterface
interface FunctionInterface3 {
String func();
}
/**
* 单参有返回值接口
*/
@FunctionalInterface
interface FunctionInterface4 {
String func(String param);
}
/**
* 多餐有返回值接口
*/
@FunctionalInterface
interface FunctionInterface5 {
String func(String param1, String param2);
}
/**
* 不使用@FunctionalInterface注解的接口
*/
interface FunctionInterface6 {
void func();
}
/**
* 不使用@FunctionalInterface注解的接口,并且有两个抽象方法
*/
interface FunctionInterface7 {
void func01();
void func02();
}
/**
* 不使用@FunctionalInterface注解的接口,并且有两个带有方法体的方法
*/
interface FunctionInterface8 {
void func01();
default void func02() {
System.out.println("default修饰的方法...");
}
static void func03() {
System.out.println("static修饰的方法...");
}
}
3. Lambda表达式代码案例
public class Demo {
public static void main(String[] args) {
// 原先使用匿名内部类方式
FunctionInterface1 func1 = new FunctionInterface1() {
@Override
public void func() {
System.out.println("未使用Lambda表达式时的匿名内部类...");
}
};
// 调用方法
func1.func();
System.out.println("=========================华丽的分割线=========================");
/**
* 无参无返回值接口
*/
// @FunctionalInterface
// interface FunctionInterface1 {
// FunctionInterface1 functionInterface1 = () -> {
// System.out.println("使用Lambda表达式创建匿名内部类...");
// };
// functionInterface1.func();
FunctionInterface1 functionInterface1 = () -> System.out.println("使用Lambda表达式创建匿名内部类");
functionInterface1.func();
System.out.println("=========================华丽的分割线=========================");
/**
* 单参无返回值接口
*/
// @FunctionalInterface
// interface FunctionInterface2 {
// 单参方式1
// FunctionInterface2 functionInterface2 = (String param) -> {
// System.out.println("传入的参数是:" + param);
// };
// functionInterface2.func("彭于晏");
// 单参方式2
// FunctionInterface2 functionInterface2 = (param) -> System.out.println("传入的参数是:" + param);
// functionInterface2.func("吴彦祖");
// 单参方式3
FunctionInterface2 functionInterface2 = param -> System.out.println("传入的参数是:" + param);
functionInterface2.func("周杰伦");
System.out.println("=========================华丽的分割线=========================");
/**
* 无参有返回值接口
*/
// @FunctionalInterface
// interface FunctionInterface3 {
// 有返回值方式1
// FunctionInterface3 functionInterface3 = () -> {
// // 返回值直接返回
// return "胡歌";
// };
// String result1 = functionInterface3.func();
// System.out.println("result1 = " + result1);
// 有返回值方式2
FunctionInterface3 functionInterface3 = () -> "鞠婧祎";
String result1 = functionInterface3.func();
System.out.println("result1 = " + result1);
System.out.println("=========================华丽的分割线=========================");
/**
* 单参有返回值接口
*/
// @FunctionalInterface
// interface FunctionInterface4 {
FunctionInterface4 functionInterface4 = param -> "返回值是:" + param;
String result2 = functionInterface4.func("刘亦菲");
System.out.println("result2 = " + result2);
System.out.println("=========================华丽的分割线=========================");
/**
* 多餐有返回值接口
*/
// @FunctionalInterface
// interface FunctionInterface5 {
// 多餐时小括号不能省略
FunctionInterface5 functionInterface5 = (param1, param2) -> param1 + "," + param2;
String result3 = functionInterface5.func("孤", "嬴政");
System.out.println("result3 = " + result3);
System.out.println("=========================华丽的分割线=========================");
/**
* 不使用@FunctionalInterface注解的接口
*/
// interface FunctionInterface6 {
FunctionInterface6 functionInterface6 = () -> System.out.println("不使用@FunctionalInterface注解的接口");
functionInterface6.func();
System.out.println("=========================华丽的分割线=========================");
/**
* 不使用@FunctionalInterface注解的接口,并且有两个抽象方法
*/
// interface FunctionInterface7 {
// 如果抽象方法有多个则无法使用Lambda表达式,原因是Lambda表达式是不需要指定方法名称的,如果存在多个抽象方法则无法确定使用的是谁
// FunctionInterface7 functionInterface7 = () -> System.out.println("不使用@FunctionalInterface注解的接口,并且有两个抽象方法");
System.out.println("=========================华丽的分割线=========================");
/**
* 不使用@FunctionalInterface注解的接口,并且有两个带有方法体的方法
*/
// interface FunctionInterface8 {
FunctionInterface8 functionInterface8 = () -> System.out.println("不使用@FunctionalInterface注解的接口,并且有两个带有方法体的方法");
functionInterface8.func01();
functionInterface8.func02();
// 静态方法通过类名直接调用
FunctionInterface8.func03();
}
}
4. Lambda表达式注意事项
- Lambda表达式形参列表可以忽略数据类型
- Lambda表达式如果是单个参数可以忽略小括号,如果是多个参数则不能忽略小括号
- Lambda表达式如果只有一行代码则可以忽略大括号,如果是多行则不能忽略大括号,如果带有返回值也是一行则也可以忽略return以及大括号
- Lambda表达式只能通过接口使用,且接口中抽象方法只允许有一个,default和static修饰的不影响
4. Lambda表达式创建对象与调用方法–>重点掌握
Lambda表达式除了可以实现匿名内部类之外还可以用于创建对象以及调用方法
1. 使用Lambda表达式创建对象
- 实体类对象
public class User {
}
- 接口
@FunctionalInterface
public interface FunctionInterface {
/**
* 使用抽象方法并返回User对象
*
* @return 返回User对象
*/
User getUser();
}
- 测试类
public class Demo {
public static void main(String[] args) {
// 不使用Lambda表达式创建对象方式
// User user = new User();
// 使用Lambda表达式创建User对象
// 方式1
// FunctionInterface fi = () -> new User();
// User user = fi.getUser();
// 方式2
// User::new-->双冒号代表调用方法,通过名称调用方法
FunctionInterface fi = User::new;
User user = fi.getUser();
System.out.println("user = " + user);
}
}
2. 使用Lambda表达式调用方法
- 接口
@FunctionalInterface
public interface FunctionInterface {
void func();
}
- 测试类
public class Demo {
public static void main(String[] args) {
// 未使用Lambda表达式时调用方法
// // 调用普通方法需要创建对象
// Demo demo = new Demo();
// demo.fun01();
// // 调用静态方法
// Demo.func02();
// 使用Lambda表达式调用普通方法
// 如果直接调用会出现错误
// FunctionInterface fi = Demo::fun01;
// 创建Demo对象,然后调用普通方法
Demo demo = new Demo();
// 函数式调用,等同于将Demo的方法通过接口实现
// 注意:对象中的方法必须与接口中的方法完全相同,方法名称可以不同
FunctionInterface fi1 = demo::fun01;
fi1.func();
// 使用Lambda表达式调用静态方法
FunctionInterface fi2 = Demo::func02;
fi2.func();
// 非简写方式
FunctionInterface fi3 = () -> demo.fun01();// 调用普通方法
FunctionInterface fi4 = () -> func02();// 调用静态方法
}
/**
* 普通方法
*/
public void fun01() {
System.out.println("func01方法被调用...");
}
/**
* 静态方法
*/
public static void func02() {
System.out.println("func02方法被调用...");
}
}
5. Java提供的Lambda表达式常用方法
1. List集合中提供的Lambda表达式
1. List集合提供的Lambda表达式方法
default void forEach(Consumer<? super T> action)
:Iterator接口的方法,主要用于遍历集合中的所有数据action
:参数类型Consumer
函数式接口
default boolean removeIf(Predicate<? super E> filter)
:Collection接口的方法,主要用于删除集合中的指定数据filter
:参数类型Predicate
函数式接口
default void sort(Comparator<? super E> c)
:List接口的方法,主要用于排列List集合数据,升序或降序c
:参数类型Comparator
函数式接口
2. List集合的Lambda表达式方法代码案例
public class Demo {
public static void main(String[] args) {
// 创建List集合对象并添加数据
List<String> list = new ArrayList<>();
// 添加数据
list.add("刘亦菲");
list.add("凤姐");
list.add("鞠婧祎");
list.add("凤姐");
list.add("王祖贤");
list.add("凤姐");
list.add("石榴姐");
list.add("凤姐");
list.add("赣州燕子");
list.add("凤姐");
// 1. `default void forEach(Consumer<? super T> action)`:Iterator接口的方法,主要用于遍历集合中的所有数据
// 1. `action`:参数类型`Consumer`函数式接口
// 不是用Lambda表达式使用forEach方法
// list.forEach(new Consumer<String>() {
// @Override
// public void accept(String s) {// List集合中有多少数据此方法就执行多少次
// System.out.println(s);
// }
// });
// 使用Lambda表达式调用方式1
// list.forEach(param -> {
// System.out.println(param);
// });
// 使用Lambda表达式调用方式2
// list.forEach(param -> System.out.println("param = " + param));
// 使用Lambda表达式调用方式3-->简写提示soutc会输出System.out::println
list.forEach(System.out::println);
// 2. `default boolean removeIf(Predicate<? super E> filter)`:Collection接口的方法,主要用于删除集合中的指定数据
// 1. `filter`:参数类型`Predicate`函数式接口
// list.removeIf(new Predicate<String>() {
// /**
// * 用于循环判断List集合中是否存在相同数据,如果存在则返回true返回true后删除
// * @param s 循环遍历List集合数据
// * @return 返回布尔类型, 如果为true则删除此数据, 否则不删
// */
// @Override
// public boolean test(String s) {
// // 将凤姐删除
// return "凤姐".equals(s);
// }
// });
// 使用Lambda表达式写法
list.removeIf(param -> "凤姐".equals(param));
// 由于String的特殊性,只要是双引号就是String类的对象,所以可以直接使用""::equals这种方式调用
list.removeIf("凤姐"::equals);
System.out.println("list = " + list);
// 3. `default void sort(Comparator<? super E> c)`:List接口的方法,主要用于排列List集合数据,升序或降序
// 1. `c`:参数类型`Comparator`函数式接口
// 正序排序
// list.sort((param1, param2) -> param1.compareTo(param2));
// 排序简写方式1
list.sort(String::compareTo);
// 排序简写方式2
list.sort(Comparator.naturalOrder());
System.out.println("list = " + list);
// 倒序排序
list.sort((param1, param2) -> param2.compareTo(param1));
list.sort(Comparator.reverseOrder());
System.out.println("list = " + list);
}
}
2. 多线程的Lambda表达式使用–>使用多线程如果不是重复利用则可以使用Lambda表达式方法创建
多线程实现Runnable接口,这个接口也是@FunctionalInterface
修饰的函数式接口,所以也可以使用Lambda表达式
代码案例
public class Demo {
public static void main(String[] args) {
// 未使用Lambda表达式前的Runnable匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("线程执行..." + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
// 使用Lambda表达式后的Runnable接口
new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.println("Lambda表达式线程执行..." + i);
}
}).start();
}
}
以上就是多线程匿名内部类使用Lambda表达式的方式
6. Lambda表达式总结
- Lambda表达式的出现就是为了简化代码(简化开发代码),使用时如果对于某个函数式接口不熟悉则很难理解,如果不指定使用的是哪个函数式接口则ctrl+左键点击
->
gose to - Lambda表达式虽然是很好用的代码格式,但是如果公司内部没有人使用则自己也需要谨慎使用,尤其是公司中老人比较多,且他们不思进取不看新的技术,则会出现他们看不懂的问题,这个时候就不要给双方找不自在
- Lambda表达式使用时注意静态方法和普通方法的调用
- 静态方法可以直接通过类调用
- 普通方法则必须是创建对象再调用的
- String类型是个列外,只要在程序中看到了说引号则代表就是一个String的对象,它可以直接调用普通方法
- Java中还提供了很多的函数式接口可以供Lambda表达式使用,所有以后只要看到了使用
@FunctionalInterface
注解的接口则都可以使用,如果接口中没有使用@FunctionalInterface
此注解但是接口中只有一个抽象方法也可以使用Lambda表达式