Lambda表达式
Lambda表达式使用的前提
Lambda表达式的语法是非常简洁的,但是Lambda表达式不是随便使用,使用时有几个条件要特别注意
1.方法的参数或局部变量类型必须为接口才能使用Lambda
2.接口中有且仅有一个抽象方法(@Functionallnterface)
使用Lambda表达式主要核心是使用在Stream流中。
使用lambda表达式的前提是该接口必须为函数式接口(有且仅有一个抽象方法)
@FunctionalInterface :该注解可以判断接口是否为函数式接口
Lambda表达式无参无返回值语法
函数式接口 变量名 =()->{方法体}
这里使用runnable举例
//匿名内部类
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("使用匿名内部类的方式执行线程任务");
}
};
//转化为lambda表达式
Runnable run =()->{
System.out.println("这是使用lambda表达式的线程任务");
};
自定义函数式接口使用Lambda表达式
public class Test02 {
public static void main(String[] args) {
fun(()-> {
System.out.println("我在lambda中游泳");
});
}
public static void fun(Swimming w){
w.crawl();
}
}
//函数式接口
@FunctionalInterface
interface Swimming{
public void crawl();
}
有参有返回值
函数式接口 变量名 =(参数1,参数2)->{方法体}
package com.cjj.demo03;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class Test03 {
public static void main(String[] args) {
ArrayList<Student> student = new ArrayList<>();
student.add(new Student("成俊杰",18));
student.add(new Student("阿光",25));
student.add(new Student("陈重豪",19));
student.add(new Student("王俊齐",28));
System.out.println(student);
/* //对集合中的元素按照年龄排序,从大到小排序
//collections:集合工具类
Comparator<Student> comparator = new Comparator<Student>() {
@Override
//如果是0表示相同,大于0表示o1大于o2
public int compare(Student o1, Student o2) {
return o1.getAge()-o2.getAge();
}
};
//collections中的排序方法,第一个参数为需要排序的集合,第二个排序的规则
Collections.sort(student,comparator);
System.out.println(student);
*/
//使用Lambda表达式的方式进行排序,有参有返回值
Comparator<Student> comparator2 = (o1,o2) ->{ //Lambda表达式就是对函数式接口中抽象方法的简写
//如果是0表示相同,大于0表示o1大于o2
return o1.getAge()-o2.getAge();
};
Collections.sort(student,comparator2);
System.out.println(student);
}
}
class Student{
String name;
int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
Lambda表达式的简写规则
1.小括号内的参数类型可以省略
2.如果小括号内有且仅有一个参数,则小括号可以省略
3.如果大括号内有且仅有一个语句,可以同时省略大括号,return关键字及语句分号
package com.cjj.demo02;
public class Test02 {
public static void main(String[] args) {
//有且仅有一个参数,省略小括号
Swimming swimming = a1-> System.out.println("输出省略小括号的语句"+a1);
fun(swimming);
//有且仅有一个语句,可以同时省略大括号,return关键字以及语句分号
Swimming2 swimming2 = a2-> a2*2;
fun2(swimming2);
}
public static void fun(Swimming w){
w.crawl(15);
}
public static void fun2(Swimming2 w2){
int i = w2.crawl2(12);
System.out.println(i);
}
}
//函数式接口
@FunctionalInterface
interface Swimming{
public void crawl(int a1);
}
@FunctionalInterface
interface Swimming2{
public int crawl2(int a2);
}
内置函数式接口
想要使用Lambda表达式,他的前提就是必须是函数式接口
内置函数式接口的由来
package com.cjj.demo04;
public class Test04 {
public static void main(String[] args) {
Operation operation = arr-> {
int sum=0;
for (int s:arr){
sum+=s;
}
return sum;
};
fun(operation);
}
public static void fun(Operation operation){
int[] arr ={1,2,3,4};
int s =operation.getSum(arr);
System.out.println("数组的和"+s);
}
}
interface Operation{
public int getSum(int[] arr);
}
分析:
我们知道使用Lambda表达式的前提是需要有函数式接口,而Lambda表达式使用时不关心接口名,抽象方法名。只关心抽象方法的参数列表和返回值类型。因此为了让我们使用Lambda表达式更加的方便,JDK内置提供了大量常用的函数式接口,大多数无需自己再定义函数式接口,而可以直接使用jdk内置的函数式接口,大约分成了四类。
消费型函数式接口Consumer
适合有参无返回值
示例:
package com.cjj.demo05;
import java.util.function.Consumer;
public class Test05 {
public static void main(String[] args) {
Consumer<Double> doubleConsumer = t-> {
System.out.println("今天吃饭花费"+t+"元");
};
fun(doubleConsumer,500.0);
}
//有参无返回值,直接使用消费型函数式接口Consumer
public static void fun(Consumer<Double> consumer , Double money){
consumer.accept(money);
}
}
供给型函数式接口Supplier
适合无参有返回值
示例:
package com.cjj.demo06;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class Test06 {
public static void main(String[] args) {
Supplier<Double> doubleSupplier = ()-> 1000.0;
fun(doubleSupplier);
}
//无参有返回值,直接使用供给型接口Supplier内置函数式接口
public static void fun(Supplier<Double> supplier){
Double aDouble = supplier.get();
System.out.println(aDouble);
}
}
函数型函数式接口--Function<T,R>
适合有参有返回值
T代表参数的类型
R代表返回值的类型
package com.cjj.demo07;
import java.util.function.Function;
import java.util.function.Supplier;
public class Test07 {
public static void main(String[] args) {
Function<Double,String> function=d-> "今天吃饭花了"+d+"元";
fun(function,25.2);
}
//有参有返回值,直接使用函数型接口Function
public static void fun(Function<Double,String> function,Double d){
String apply = function.apply(d);
System.out.println(apply);
}
}
断言型函数式接口Predicate
判断是否满足条件
T为参数
boolean为返回值类型
package com.cjj.demo08;
import java.util.function.Function;
import java.util.function.Predicate;
public class Test08 {
public static void main(String[] args) {
Predicate<Integer> predicate =t->t>=19;
fun(predicate,18);
}
//判断是否满足条件,直接使用函数型接口Predicate
public static void fun(Predicate<Integer> predicate, Integer d){
boolean test = predicate.test(d);
System.out.println("是否成年"+test);
}
}
方法引用
特殊的Lambda表达式,它是对Lambda表达式的一种简写方式。
类名::方法名
方法引用的由来
package com.cjj.demo09;
import java.util.function.Consumer;
public class Test09 {
public static void main(String[] args) {
Consumer<int[]> consumer=t->{
int sum=0;
for (int i : t) {
sum+=i;
}
System.out.println("数组的和"+sum);
};
fun(consumer);
}
public static void fun(Consumer<int[]> consumer){
int[] arr = {1,2,3,4,5,6};
consumer.accept(arr);
}
public static void sum(int[] arr){
int sum =0;
for (int i : arr) {
sum+=i;
}
System.out.println("数组的和是"+sum);
}
}
分析:
如果我们在Lambda表达式中所指定的功能,已经有其他方法存在相同方案,那是否还有必要再写重复的逻辑?可以直接"引用过去就好了":---方法引用
上面案例经过方法引用改变后的代码如下:
package com.cjj.demo09;
import java.util.function.Consumer;
public class Test09 {
public static void main(String[] args) {
Consumer<int[]> consumer=Test09::sum;
fun(consumer);
}
public static void fun(Consumer<int[]> consumer){
int[] arr = {1,2,3,4,5,6};
consumer.accept(arr);
}
public static void sum(int[] arr){
int sum =0;
for (int i : arr) {
sum+=i;
}
System.out.println("数组的和是"+sum);
}
}
package com.cjj.demo09;
import java.util.function.Consumer;
public class Test09 {
public static void main(String[] args) {
fun(Test09::sum);
}
public static void fun(Consumer<int[]> consumer){
int[] arr = {1,2,3,4,5,6};
consumer.accept(arr);
}
public static void sum(int[] arr){
int sum =0;
for (int i : arr) {
sum+=i;
}
System.out.println("数组的和是"+sum);
}
}
方法引用的类型
方法引用是Lambda表达式中的一种简写。如果lambda表达式方法体中只是调用一个特定的已经存在的方法,则可以使用方法引用。
静态方法引用
(args)->类型.静态方法(args). 当Lambda表达式中的方法体,只有一条语句,而这条语句是类型.静态方法。并且静态方法的参数和lambda的参数一致时。
类名::静态方法;
实例方法引用
(args)->inst.instMethod(args)
实例方法引用,顾名思义就是调用已经存在的实例的方法,与静态方法引用不同的是类要先实例化,静态方法引用 类无需实例化,直接用类名去调用
类名::方法名
public class Test10 {
public static void main(String[] args) {
//创建一个实例对象
Student s = new Student("cjj",21);
//lambda表达式
Supplier<String> supplier = ()->s.getName();
String s2 = supplier.get();
System.out.println(s2);
//方法引用
Supplier<String> sup=s::getName;
//拿到返回值
String s1 = sup.get();
System.out.println(s1);
}
}
class Student{
String name;
Integer age;
public Student() {
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public Integer getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(Integer age) {
this.age = age;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
对象方法引用
lambda: (inst,args)->inst.普通方法(args)----->类名::普通方法
若lambda参数类列表中的第一个参数是实例方法的参数调用者,而第二个参数是实例方法的参数时,可以使用对象方法引用。
public class Test11 {
public static void main(String[] args) {
//使用lambda表达式判断两个字符串是否一致
BiFunction<String,String,Boolean> biFun = (s1,s2)->s1.equals(s2);
Boolean apply = biFun.apply("cjj", "cjj");
System.out.println(apply);
//转换为对象方法引用的方式判断
BiFunction<String,String,Boolean> biFun2 = String::equals;
Boolean apply2 = biFun.apply("cjj", "cjj");
System.out.println(apply2);
}
}
构造方法引用
(args)->new 类名(args)
类名::new
public class Test12 {
public static void main(String[] args) {
//lambda 无参有返回值
Supplier<Student> supplier = ()->new Student();
final Student student = supplier.get();
System.out.println(student);
//转换为构造方法引用
Supplier<Student> supplier2 = Student::new;
final Student student2 = supplier2.get();
System.out.println(student2);
//lambda有参有返回值
BiFunction<String,Integer,Student> biFunction=(n,a)->new Student(n,a);
Student cjj = biFunction.apply("cjj", 22);
System.out.println(cjj);
//转换为构造方法引用
BiFunction<String,Integer,Student> biFunction2=Student::new;
Student cjj2 = biFunction.apply("cjj", 23);
System.out.println(cjj2);
}
}