Java基础(二十五):Lambda表达式、方法引用、构造器引用

Java基础系列文章

Java基础(一):语言概述Java基础(二):原码、反码、补码及进制之间的运算Java基础(三):数据类型与进制Java基础(四):逻辑运算符和位运算符
Java基础(五):流程控制语句Java基础(六):数组Java基础(七):面向对象编程Java基础(八):封装、继承、多态性
Java基础(九):Object 类的使用Java基础(十):关键字static、代码块、关键字finalJava基础(十一):抽象类、接口、内部类Java基础(十二):枚举类
Java基础(十三):注解(Annotation)Java基础(十四):包装类Java基础(十五):异常处理Java基础(十六):String的常用API
Java基础(十七):日期时间APIJava基础(十八):java比较器、系统相关类、数学相关类Java基础(十九):集合框架Java基础(二十):泛型
Java基础(二十一):集合源码Java基础(二十二):File类与IO流Java基础(二十三):反射机制Java基础(二十四):网络编程
Java基础(二十五):Lambda表达式、方法引用、构造器引用Java基础(二十六):Java8 Stream流及Optional类


一、Lambda表达式

1、语法

  • Lambda 表达式:在Java 8 语言中引入的一种新的语法元素和操作符
  • 这个操作符为 “->” , 该操作符被称为Lambda操作符箭头操作符
  • 它将 Lambda 分为两个部分:
    • 左侧:指定了 Lambda 表达式需要的参数列表
    • 右侧:指定了 Lambda 体,是抽象方法的实现逻辑,也即 Lambda 表达式要执行的功能

语法格式一:无参,无返回值

  • run方法名省略,保留无参()和具体实现类{内容}
@Test
public void test1(){
    //未使用Lambda表达式
    Runnable r1 = new Runnable() {
        @Override
        public void run() {
            System.out.println("我爱北京天安门");
        }
    };

    r1.run();

    System.out.println("***********************");

    //使用Lambda表达式
    Runnable r2 = () -> {
        System.out.println("我爱北京故宫");
    };

    r2.run();
}

语法格式二:一个参数,但是没有返回值

  • 只保留参数(类型 变量)和具体实现类{内容}
@Test
public void test2(){
    //未使用Lambda表达式
    Consumer<String> con = new Consumer<String>() {
        @Override
        public void accept(String s) {
            System.out.println(s);
        }
    };
    con.accept("谎言和誓言的区别是什么?");

    System.out.println("*******************");

    //使用Lambda表达式
    Consumer<String> con1 = (String s) -> {
        System.out.println(s);
    };
    con1.accept("一个是听得人当真了,一个是说的人当真了");
}

语法格式三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”

@Test
public void test3(){
    //语法格式三使用前
    Consumer<String> con1 = (String s) -> {
        System.out.println(s);
    };
    con1.accept("一个是听得人当真了,一个是说的人当真了");

    System.out.println("*******************");
    //语法格式三使用后
    Consumer<String> con2 = (s) -> {
        System.out.println(s);
    };
    con2.accept("一个是听得人当真了,一个是说的人当真了");
}

语法格式四:若只需要一个参数时,参数的小括号可以省略

@Test
public void test4(){
    //语法格式四使用前
    Consumer<String> con1 = (s) -> {
        System.out.println(s);
    };
    con1.accept("一个是听得人当真了,一个是说的人当真了");

    System.out.println("*******************");
    //语法格式四使用后
    Consumer<String> con2 = s -> {
        System.out.println(s);
    };
    con2.accept("一个是听得人当真了,一个是说的人当真了");
}

语法格式五:当Lambda体只有一条语句时,return与大括号若有,都可以省略

@Test
public void test5(){
    //语法格式五使用前
    Comparator<Integer> com1 = (o1,o2) -> {
        return o1.compareTo(o2);
    };

    System.out.println(com1.compare(12,6));

    System.out.println("*****************************");
    //语法格式五使用后
    Comparator<Integer> com2 = (o1,o2) -> o1.compareTo(o2);

    System.out.println(com2.compare(12,21));
}

语法格式六:需要两个或以上的参数,多条执行语句,并且可以有返回值

@Test
public void test6(){
    //语法格式六使用前
    Comparator<Integer> com1 = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            System.out.println(o1);
            System.out.println(o2);
            return o1.compareTo(o2);
        }
    };

    System.out.println(com1.compare(12,21));
    System.out.println("*****************************");
    //语法格式六使用后
    Comparator<Integer> com2 = (o1,o2) -> {
        System.out.println(o1);
        System.out.println(o2);
        return o1.compareTo(o2);
    };
    System.out.println(com2.compare(12,6));
}

Lambda表达式的语法规则总结

  • -> 的左边:lambda形参列表,参数的类型都可以省略。如果形参只有一个,则一对()也可以省略
  • -> 的右边:lambda体,对应着重写的方法的方法体。如果方法体中只有一行执行语句,则一对{}可以省略。如果有return关键字,则必须一并省略

2、函数式(Functional)接口

  • 只包含一个抽象方法的接口,称为函数式接口。当然该接口可以包含其他非抽象方法
  • 可以在一个接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口
  • java.util.function包下定义了Java 8 的丰富的函数式接口

2.1、四大核心函数式接口

函数式接口称谓参数类型用途
Consumer<T> 消费型接口T对类型为T的对象应用操作
包含方法: void accept(T t)
Supplier<T> 供给型接口返回类型为T的对象
包含方法:T get()
Function<T, R> 函数型接口T对类型为T的对象应用操作,并返回结果。结果是R类型的对象
包含方法:R apply(T t)
Predicate<T> 判断型接口T确定类型为T的对象是否满足某约束,并返回boolean值
包含方法:boolean test(T t)

消费型接口

在这里插入图片描述

@Test
public void test1() {
    List<String> list = Arrays.asList("hello", "java", "lambda");
    list.forEach(s -> System.out.println(s));
}

供给型接口

在这里插入图片描述

@Test
public void test2() {
    // 返回一个无限连续的无序流,其中每个元素都由提供的 Supplier 生成
    // 这适用于生成恒定流、随机元素流等
    Stream.generate(() -> Math.random()).forEach(System.out::println);
}

功能型接口

在这里插入图片描述

@Test
public void test3() {
    HashMap<Integer, String> map = new HashMap<>();
    map.put(1, "100");
    map.put(2, "200");
    map.put(3, "300");
    map.put(4, "400");
    map.put(5, "500");
    // 如果k为偶数,则返回v + "00",否则返回v
    map.replaceAll((k, v) -> {
        if (k % 2 == 0){
            return v + "00";
        }
        return v;
    });
    map.forEach((k, v) -> System.out.println(k + "=" + v));
}

功能型接口

在这里插入图片描述

@Test
public void test4() {
    ArrayList<String> list = new ArrayList<>();
    list.add("hello");
    list.add("java8");
    list.add("ok");
    list.add("yes");
    // 移除所有长度小于5的元素
    list.removeIf(str -> str.length() < 5);
    list.forEach(str -> System.out.println(str)); // hello java8
}

2.2、消费型接口

  • 消费型接口的抽象方法特点:有形参,但是返回值类型是void
接口名抽象方法描述
BiConsumer<T,U>void accept(T t, U u)接收两个对象用于完成功能
DoubleConsumervoid accept(double value)接收一个double值
IntConsumervoid accept(int value)接收一个int值
LongConsumervoid accept(long value)接收一个long值
ObjDoubleConsumervoid accept(T t, double value)接收一个对象和一个double值
ObjIntConsumervoid accept(T t, int value)接收一个对象和一个int值
ObjLongConsumervoid accept(T t, long value)接收一个对象和一个long值

2.3、供给型接口

  • 供给型接口的抽象方法特点:无参,但是有返回值
接口名抽象方法描述
BooleanSupplierboolean getAsBoolean()返回一个boolean值
DoubleSupplierdouble getAsDouble()返回一个double值
IntSupplierint getAsInt()返回一个int值
LongSupplierlong getAsLong()返回一个long值

2.4、函数型接口

  • 函数型接口的抽象方法特点:既有参数又有返回值
接口名抽象方法描述
UnaryOperatorT apply(T t)接收一个T类型对象,返回一个T类型对象结果
DoubleFunctionR apply(double value)接收一个double值,返回一个R类型对象
IntFunctionR apply(int value)接收一个int值,返回一个R类型对象
LongFunctionR apply(long value)接收一个long值,返回一个R类型对象
ToDoubleFunctiondouble applyAsDouble(T value)接收一个T类型对象,返回一个double
ToIntFunctionint applyAsInt(T value)接收一个T类型对象,返回一个int
ToLongFunctionlong applyAsLong(T value)接收一个T类型对象,返回一个long
DoubleToIntFunctionint applyAsInt(double value)接收一个double值,返回一个int结果
DoubleToLongFunctionlong applyAsLong(double value)接收一个double值,返回一个long结果
IntToDoubleFunctiondouble applyAsDouble(int value)接收一个int值,返回一个double结果
IntToLongFunctionlong applyAsLong(int value)接收一个int值,返回一个long结果
LongToDoubleFunctiondouble applyAsDouble(long value)接收一个long值,返回一个double结果
LongToIntFunctionint applyAsInt(long value)接收一个long值,返回一个int结果
DoubleUnaryOperatordouble applyAsDouble(double operand)接收一个double值,返回一个double
IntUnaryOperatorint applyAsInt(int operand)接收一个int值,返回一个int结果
LongUnaryOperatorlong applyAsLong(long operand)接收一个long值,返回一个long结果
BiFunction<T,U,R>R apply(T t, U u)接收一个T类型和一个U类型对象,返回一个R类型对象结果
BinaryOperatorT apply(T t, T u)接收两个T类型对象,返回一个T类型对象结果
ToDoubleBiFunction<T,U>double applyAsDouble(T t, U u)接收一个T类型和一个U类型对象,返回一个double
ToIntBiFunction<T,U>int applyAsInt(T t, U u)接收一个T类型和一个U类型对象,返回一个int
ToLongBiFunction<T,U>long applyAsLong(T t, U u)接收一个T类型和一个U类型对象,返回一个long
DoubleBinaryOperatordouble applyAsDouble(double left, double right)接收两个double值,返回一个double结果
IntBinaryOperatorint applyAsInt(int left, int right)接收两个int值,返回一个int结果
LongBinaryOperatorlong applyAsLong(long left, long right)接收两个long值,返回一个long结果

2.5、判断型接口

  • 判断型接口的抽象方法特点:有参,但是返回值类型是boolean结果
接口名抽象方法描述
BiPredicate<T,U>boolean test(T t, U u)接收两个对象
DoublePredicateboolean test(double value)接收一个double值
IntPredicateboolean test(int value)接收一个int值
LongPredicateboolean test(long value)接收一个long值

二、方法引用

  • 方法引用,可以看做是基于lambda表达式的进一步简化

1、方法引用格式

  • 情况1:对象 :: 实例方法名
    • 函数式接口中的抽象方法a在被重写时使用了某一个对象的方法b
    • 如果方法a的形参列表、返回值类型与方法b的形参列表、返回值类型都相同
    • 则我们可以使用方法b实现对方法a的重写、替换
  • 情况2:类 :: 静态方法名
    • 函数式接口中的抽象方法a在被重写时使用了某一个类的静态方法b
    • 如果方法a的形参列表、返回值类型与方法b的形参列表、返回值类型都相同
    • 则我们可以使用方法b实现对方法a的重写、替换
  • 情况3:类 :: 实例方法名
    • 函数式接口中的抽象方法a在被重写时使用了某一个对象的方法b
    • 如果方法a的返回值类型与方法b的返回值类型相同
    • 同时方法a的形参列表中有n个参数,方法b的形参列表有n-1个参数
    • 且方法a的第1个参数作为方法b的调用者,且方法a的后n-1参数与方法b的n-1参数匹配

2、举例

情况一:对象 :: 实例方法

  • Consumer中的void accept(T t)与PrintStream中的void println(T t)参数返回值相同
  • 后者直接替换掉前者
@Test
public void test1() {
	Consumer<String> con1 = str -> System.out.println(str);
	con1.accept("北京");

	System.out.println("*******************");
	PrintStream ps = System.out;
	Consumer<String> con2 = ps::println;
	con2.accept("beijing");
}
  • Supplier<String>中的T get()与Employee中的String getName()参数返回值相同
@Test
public void test2() {
	Employee emp = new Employee(1001,"Tom",23,5600);

	Supplier<String> sup1 = () -> emp.getName();
	System.out.println(sup1.get());

	System.out.println("*******************");
	Supplier<String> sup2 = emp::getName;
	System.out.println(sup2.get());
}

情况二:类 :: 静态方法

  • Comparator中的int compare(T t1,T t2)与Integer中的静态方法int compare(T t1,T t2)参数返回值相同
@Test
public void test3() {
	Comparator<Integer> com1 = (t1,t2) -> Integer.compare(t1,t2);
	System.out.println(com1.compare(12,21));

	System.out.println("*******************");

	Comparator<Integer> com2 = Integer::compare;
	System.out.println(com2.compare(12,3));
}
  • Function中的R apply(T t)与Math中的静态方法Long round(Double d)参数返回值相同
@Test
public void test4() {
	Function<Double,Long> func = new Function<Double, Long>() {
		@Override
		public Long apply(Double d) {
			return Math.round(d);
		}
	};

	System.out.println("*******************");

	Function<Double,Long> func1 = d -> Math.round(d);
	System.out.println(func1.apply(12.3));

	System.out.println("*******************");

	Function<Double,Long> func2 = Math::round;
	System.out.println(func2.apply(12.6));
}

情况三:类 :: 实例方法

  • a抽象方法第一个参数s1为b方法调用者,a抽象方法其他参数为b方法参数
@Test
public void test5() {
	Comparator<String> com1 = (s1,s2) -> s1.compareTo(s2);
	System.out.println(com1.compare("abc","abd"));

	System.out.println("*******************");

	Comparator<String> com2 = String :: compareTo;
	System.out.println(com2.compare("abd","abm"));
}
  • Function中的R apply(T t)与Employee中的String getName()返回值一样
  • e -> e.getName():第一参数e为后者的调用者
@Test
public void test6() {
	Employee employee = new Employee(1001, "Jerry", 23, 6000);

	Function<Employee,String> func1 = e -> e.getName();
	System.out.println(func1.apply(employee));

	System.out.println("*******************");
	Function<Employee,String> func2 = Employee::getName;
	System.out.println(func2.apply(employee));
}

三、构造器引用

  • 当Lambda表达式是创建一个对象,并且满足Lambda表达式形参正好是给创建这个对象的构造器的实参列表,就可以使用构造器引用
  • 格式:类名::new

空参构造器

@Test
public void test1(){
    Supplier<Employee> sup = new Supplier<Employee>() {
        @Override
        public Employee get() {
            return new Employee();
        }
    };
    System.out.println("*******************");

    Supplier<Employee>  sup1 = () -> new Employee();
    System.out.println(sup1.get());

    System.out.println("*******************");

    Supplier<Employee>  sup2 = Employee :: new;
    System.out.println(sup2.get());
}

多参构造器

  • 相当于BiFunction中的R apply(T t,U u)中的参数赋值给new Employee(id,name)
@Test
public void test2(){
    BiFunction<Integer,String,Employee> func1 = (id,name) -> new Employee(id,name);
    System.out.println(func1.apply(1001,"Tom"));

    System.out.println("*******************");

    BiFunction<Integer,String,Employee> func2 = Employee :: new;
    System.out.println(func2.apply(1002,"Tom"));
}

四、数组构造引用

  • 当Lambda表达式是创建一个数组对象,并且满足Lambda表达式形参正好是给创建这个数组对象的长度,就可以数组构造引用
  • 格式:数组类型名::new
@Test
public void test3(){
    Function<Integer,String[]> func1 = length -> new String[length];
    String[] arr1 = func1.apply(5);
    System.out.println(Arrays.toString(arr1));

    System.out.println("*******************");

    Function<Integer,String[]> func2 = String[] :: new;
    String[] arr2 = func2.apply(10);
    System.out.println(Arrays.toString(arr2));
}

总结

  • 只要看起来没有歧义,只能仅有调用某个方法,传入某些参数,就可以简化为Lambda表达式或方法构造器引用
  • 18
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Lambda表达式条件构造器用于在Lambda表达式中根据条件来构造不同的结果。它可以根据给定的条件返回不同的表达式或语句。具体来说,Lambda表达式条件构造器可以使用if语句或者三元运算符来实现条件判断。 使用if语句的Lambda表达式条件构造器的语法如下: (parameters) -> { if (condition) { // 执行条件为真的语句 return expression1; } else { // 执行条件为假的语句 return expression2; } } 使用三元运算符的Lambda表达式条件构造器的语法如下: (parameters) -> condition ? expression1 : expression2 注意,expression1和expression2可以是表达式或者语句块。条件构造器可以根据需要自由组合和嵌套,以实现更复杂的条件逻辑。 方法引用是对Lambda表达式符合某种情况下的一种缩,使得我们的Lambda表达式更加精简。当Lambda表达式中的逻辑非常简单且只调用了一个已存在的方法时,可以考虑使用方法引用方法引用通过引用已存在的方法来替代Lambda表达式,使代码更加简洁和易读。方法引用的语法格式为:类名::方法名。 总结一下,Lambda表达式条件构造器用于根据条件来构造不同的结果,可以使用if语句或者三元运算符来实现。方法引用是对符合某种情况下的Lambda表达式的一种缩,用于替代Lambda表达式中调用已存在方法的情况,使代码更简洁。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Java学习day042 lambda表达式构造器引用、变量作用域、处理lambda表达式、再谈Comparator)](https://blog.csdn.net/Zzehao11/article/details/105415027)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [java8新特性之lambda表达式(及方法引用构造器引用)](https://blog.csdn.net/cristianoxm/article/details/110222407)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冬天vs不冷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值