关于lambda,我有话想说
lambda作为java8更新后的新特性,其作用是为了解决冗余的代码量,使代码更加简单
lambda表达式更关注于结果而不是过程
首先明确lambda的使用前提
1.lambda的使用必须有接口的存在,且接口只有一个抽象方法(函数式接口 ).
2.lambda的使用必须具有上下文推断,也就是方法的参数或局部变量必须为lambda类型对应的接口类型
函数式接口
只有一个抽象方法的接口 @FunctionalInterface修饰 @FunctionalInterface可以起到校验的作用。
常见的函数式接口:
Runnable - 线程的接口 run()
Comparator - 比较器接口 compare(T o1,T o2)
注:查API发现Comparator有两个抽象方法,但equals重写了超类Object类中任意一个public方法的方法。并不算入接口中的抽象方法
Consumer接口 - 消费型接口 accept(T t)
Supplier接口 - 生产型接口 ,指定接口的泛型是什么类型,那么接口中的get方法就会产生什么类型的数据 get()
Function接口 - 将一个数据类型转换为另一个数据类型 跟map的形式有点像泛型中有两个前面是要被改的数据类型,后面是被改后的数据类型 accept()
Predicate接口 - 对某种数据类型的数据进行判断,结果返回一个boolean值 test(T t)
lambda 的格式
(参数类型 参数名称) -> { 代码语句 }
省略规则:
在Lambda标准格式的基础上,使用省略写法的规则为:
- 小括号内参数的类型可以省略;
- 如果小括号内有且仅有一个参,则小括号可以省略;
- 如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及语句分号。要省略三个必须一起省略不能单独省略
lambda的使用演示
接口中的应用
/*
创建Runnable接口的实现类,重写run方法,设置线程任务
*/
public class RunnableImpl implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "新线程创建了");
}
}
public class Demo01Runnable {
public static void main(String[] args) {
// 创建Runnable接口的实现类对象
RunnableImpl run = new RunnableImpl();
Thread t = new Thread(run);
// 调用start方法开启新线程,执行run方法
t.start();
// 简化代码,使用匿名内部类
Runnable r = new Runnable(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName() +
"新线程创建了");
}
};
new Thread().start();
// 简化代码
new Thread(new Runnable(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "新线程创建了");
}
}).start();
}
}
public class Demo02Lambda {
public static void main(String[] args) {
// 使用匿名内部类
new Thread(new Runnable(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "新线程创建了");
}
}).start();
// lambda 表达式
new Thread(() ->{
System.out.println(Thread.currentThread().getName() + "新线程创建了");
}).start();
// 优化省略lambda
new Thread(() ->
System.out.println(Thread.currentThread().getName() + "新线程创建了")).start();
}
}
自定义接口
public interface Cook {
// 定义无参数无返回值的方法
public abstract void makefood();
}
/*
需求:
给定一个厨子Cook接口,内含唯一的抽象方法makeFood,且无参数,无返回值
使用Lambda的标准格式调用invokeCook方法,打印输出"吃饭啦!"字样
*/
public class Demo01Cook {
public static void main(String[] args) {
// 调用invokeCook方法,参数是Cook接口,传递Cook接口的匿名内部类对象
invokeCook(new Cook() {
@Override
public void makefood() {
System.out.println("吃饭了");
}
});
// 使用Lambda表达式,简化匿名内部类的书写
invokeCook(() ->{
System.out.println("吃饭了");
});
// 优化省略lambda
invokeCook(() ->
System.out.println("吃饭了"));
}
// 定义一个方法,参数传递Cook接口,方法内部调用Cook接口中的方法
public static void invokeCook(Cook cook){
cook.makefood();
}
}
有参数有返回值使用lambda
public class Person {
String name;
int age;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
import java.util.Arrays;
import java.util.Comparator;
/*
Lambda表达式有参数有返回值的练习
需求:
使用数组存储多个Person对象
对数组中的Person对象使用Arrays的sort方法通过年龄进行升序排序
*/
public class Demo01Arrays {
public static void main(String[] args) {
// 使用数组存储多个Person对象
Person[] arr = {
new Person("柳岩",38),
new Person("迪丽热巴",14),
new Person("古力娜扎",24),
};
//对数组中的Person对象使用Arrays的sort方法通过年龄进行升序排序
/* Arrays.sort(arr, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.getAge() - o2.getAge();
}
});*/
// 使用Lambda表达式,简化匿名内部类
Arrays.sort(arr,(Person o1,Person o2) ->{
return o1.getAge() - o2.getAge();
});
// 遍历数组
// 优化省略
Arrays.sort(arr,( o1, o2) ->
o1.getAge() - o2.getAge());
// 遍历数组
for (Person person : arr) {
System.out.println(person);
}
}
}
有参数没有方法
/*
内含一个计算器Calculator接口,内含抽象方法calc可以将两个int数字相加得到和值
*/
public interface Calculator {
int calc(int a ,int b);
}
public class Demo01InvokeCalc {
public static void main(String[] args) {
invokeCalc(120,130,(int a , int b) ->{
return a + b;
});
// 优化省略
invokeCalc(120,130,(a ,b) -> a + b );
}
private static void invokeCalc(int a, int b,Calculator calculator){
int result = calculator.calc(a,b);
System.out.println("结果是:" + result);
}
}
接口作为参数
/*
假设有一个startThread方法使用该接口作为参数,那么就可以使用Lambda进行传参
*/
public class Demo01Runnable {
// 定义一个方法startThread,方法的参数使用函数式接口Runnable
public static void startThread(Runnable run){
new Thread(run).start();
}
public static void main(String[] args) {
// 调用startThread方法,方法的参数是一个接口,那么我们可以传递这个接口的匿名内部类
startThread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "->" + "线程启动了");
}
});
// 方法收的参数是一个函数式接口,可以传递Lambda表达式
startThread(()-> System.out.println(Thread.currentThread().getName() + "->" + "线程启动了"));
}
}
Supplier接口作为参数
public class Demo01Supplier {
// 定义一个方法,方法的参数传递Supplier<T>接口,泛型执行String,get方法就会返回一个String
public static String getString(Supplier<String> sup){
return sup.get();
}
public static void main(String[] args) {
// 调用getString方法,方法的参数Supplier是一个函数式接口,所以可以传递Lambda表达式
String s = getString(() ->{
return "胡歌";
});
System.out.println(s);
}
}
Consumer接口作为参数
import java.util.function.Consumer;
public class Demo01Consumer {
/*
定义一个方法
方法的参数传递一个字符串的姓名
方法的参数传递Consumer接口,泛型使用String
可以使用Consumer接口消费字符串的姓名
*/
public static void method(String name, Consumer<String> con){
con.accept(name);
}
public static void main(String[] args) {
// 调用method方法,传递字符串姓名
method("张三",(name)->{
// 对传递的字符串消费
// 直接输出去字符串
//System.out.println(name);
// 消费方式:把字符串进行反转输出
String rename = new StringBuilder().reverse().toString();
System.out.println(rename);
});
}
}
Predicate接口作为参数
import java.util.function.Predicate;
/**
* @author:chenliuyiding
* @date 2020/6/25 21: 24:
* @description
* Predicate 接口
* 作用:对某种数据类型的数据进行判断,结果返回一个boolean值
**/
public class Demo01Predicate {
/**
*定义一个方法
*参数传递一个String类型的字符串
* 传递一个Predicate接口,泛型使用String
* 使用Predicate中的方法test对字符串进行判断,并把判断的结果返回
*/
public static boolean checkString(String s, Predicate<String> pre){
return pre.test(s);
}
public static void main(String[] args) {
// 定义一个字符串
String s = "abcde";
// 调用checkString方法对字符串进行校验,参数传递字符串和Lambda表达式
/* boolean b = checkString(s, (String str) -> {
// 对参数传递的字符串进行判断,判断字符串的长度是否大于5,并把判断的结果返回
return str.length() > 5;
});*/
// 优化lambda
boolean b = checkString(s, str -> str.length() > 5);
System.out.println(b);
}
}
Function接口作为参数
import java.util.function.Function;
/**
* @author:chenliuyiding
* @date 2020/6/26 13: 02:
* @description
* 作用 将一个数据类型转换为另一个数据类型
**/
public class Demo01Function {
/**
* 定义一个方法
* 方法的参数传递一个字符串类型的整数
* 方法的参数传递一个Function接口,泛型使用<String,Integer>
* 使用Function接口中的方法apply,把字符串类型的整数,转换为Integer类型的整数
*/
public static void change(String s, Function<String ,Integer> fun){
Integer in = fun.apply(s);
System.out.println(in);
}
public static void main(String[] args) {
// 定义一个字符串类型的整数
String s = "1234";
// 调用change方法,传递字符串类型的整数,和lambda表达式
change(s,(String str) ->{
return Integer.parseInt(str);
});
}
}
总结
文章详细的说明了lambda的概念和lambda比较常用的方法,希望对大家有所帮助。