Java中的函数式编程Lambda、方法引用详解

 更新时间:2025年12月17日 11:27:30   作者:不懒的懒羊羊.  
函数式编程通过引入函数来解决问题,强调输入一致输出一致,Lambda表达式是Java 8引入的一种简洁的语法,用于替代匿名内部类,简化代码并提高可读性,本文给大家介绍Java—函数式编程(Lambda、方法引用),感兴趣的朋友跟随小编一起看看吧

引入

函数式编程中“函数”类似于数学中的函数(强调做什么),只要输入的数据一致返回的结果也是一致的

函数式编程解决了什么问题?什么是函数式编程?

使用Lambda函数替代吗某些匿名内部类对象,从而让程序代码更简洁,可读性更好。

一:Lambda

1、认识Lambda表达式

  • JDK8开始新增的一种语法形式,它表示函数。
  • 可以用于替代匿名内部类对象,从而让程序更简洁,可读性更好。
  • 注意:Lambda表达式只能替代函数式接口的匿名内部类!!!!。

什么是函数式接口

  • 且仅有一个抽象方法接口。

思考为什么只能替代函数式接口的匿名内部类,分析:函数式接口只能有一个抽象方法,在简化的时候,会找到这个抽象方法并为这个方法重写。如果有多个抽象方法,简化后:编译器不知道要为那个抽象方法重写。

Lambda表达式的书写格式

(参数列表) -> { 表达式或语句块 }
  • (参数列表):定义 Lambda 表达式接受的参数。参数的类型通常可以由编译器推断,因此可以省略。
  • ->:称为 Lambda 操作符 或 箭头操作符。它将参数列表与 Lambda 主体分隔开。
  • { 表达式或语句块 }:Lambda 表达式的主体,包含要执行的代码。
  • 如果表达式或语句块:只有一句{ }可以省略,否则不可省略。

Test类:代码1演示了:注意:Lambda表达式只能替代函数式接口的匿名内部类!!!!。

public class Test {
    public static void main(String[] args) {
        System.out.println("______________抽象类的匿名内部类_____________");
        Animal animal = new Animal() {
            @Override
            public void cry() {
                System.out.println("猫喵喵喵~~");
            }
        };
        animal.cry();
        System.out.println("______________简化抽象类的匿名内部类(报错)_____________");
        //Lambda简化匿名内部类
        //下面代码出错,Lambda表达式只能替代函数式接口的匿名内部类!!!!。
//        Animal animal = ()->{
//            System.out.println("猫喵喵喵~~");
//        };
        System.out.println("______________接口的匿名内部类_____________");
        Swim s = new Swim() {
            @Override
            public void swiming() {
                System.out.println("狗游游游~~");
            }
        };//分号不能忘
        s.swiming();
        System.out.println("______________简化函数式接口的匿名内部类_____________");
        Swim s1 = () -> {
            System.out.println("狗游游游~~");
        };
        s1.swiming();
    }
}
//动物类
abstract class Animal {
    abstract void cry();
}
//写一个游泳接口
@FunctionalInterface //声明函数式接口 ,函数式接口只能有一个抽象方法,
                     // 如果有多个抽象方法,使用注解声明后会报错
interface Swim {
    void swiming();
}
/*
输出:
______________抽象类的匿名内部类_____________
猫喵喵喵~~
______________简化抽象类的匿名内部类(报错)_____________
______________接口的匿名内部类_____________
狗游游游~~
______________简化函数式接口的匿名内部类_____________
狗游游游~~
 */

2、Lambda实战实例、省略规则

1.使用Lambda简化comparator接口的匿名内部类

2.Lambda表达式的省略规则

作用:用于进一步简化Lambda表达式写法。

具体规则:

  • 参数类型全部可以省略不写。
  • 如果只有一个参数,参数类型省略的同时“()”也可以省略,但是对个参数不能省略“()”。
  • 如果Lambda表达式中只有一行代码,大括号可以不写,同时要省略分号“;” 如果这行代码是return语句,也必须去掉return。

代码2:下面是comparator接口sort对学生对象排序的代码简化过程。在上篇文章匿名内部类中给过这个代码的完整版本。

//        Arrays.sort( s, new Comparator<Student>() {
//            @Override
//            public  int compare(Student o1, Student o2) {
//                return o1.getAge() - o2.getAge();
//            }
//        });
//        Arrays.sort( s, (Student o1, Student o2) -> {
//            return o1.getAge() - o2.getAge();
//        });
//        Arrays.sort( s, ( o1,  o2) -> {
//            return o1.getAge() - o2.getAge();
//        });
        Arrays.sort( s, ( o1,  o2) -> o1.getAge() - o2.getAge());

二、方法引用

1、静态方法引用

        静态方法引用(Static Method Reference) 是一种特殊的语法,用于直接引用一个类的静态方法,并将其作为函数式接口的实例。它是 Lambda 表达式的更简洁替代形式。

语法:

类名::静态方法名
  • 类名: 定义了静态方法的类的名称。
  • ::方法引用操作符。
  • 静态方法名: 要引用的静态方法的名称,不带括号 () 和参数。

使用场景

        如果某个Lambda表达式里只是调用一个静态方法,并且“—>”前后参数的形式一致,(就像是下面的例子,->两边都是o1、o2)就可以使用静态方法引用。

代码3:下面代码演示了静态方法引用的使用场景

Student 类

public class Student {
    private String name;
    private int age;
    //构造器
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    //静态 方法引用
    public static int compare(Student o1, Student o2){
        return o1.getAge() - o2.getAge();
    }
}

Test类

import java.util.Arrays;
public class Test {
    public static void main(String[] args) {
        Student []s = new Student[5];
        s[0] = new Student("张三", 18);
        s[1] = new Student("李四", 19);
        s[2] = new Student("张三", 50);
        s[3] = new Student("李白", 5);
        s[4] = new Student("王五", 10);
        print(s);
//        Arrays.sort(s,(o1, o2)-> o1.getAge() - o2.getAge());
//        Arrays.sort(s, (o1, o2)->Student.compare(o1, o2));
        //静态方法引用
        Arrays.sort(s,Student::compare);
        System.out.println("-------排序后:-------");
        print(s);
    }
    //打印姓名和年龄
    public static void print(Student []s){
        for (int i = 0; i < s.length; i++){
            System.out.println(s[i]);
        }
    }
}

2、实例方法引用

语法

对象名::实例方法

使用场景

        如果某个Lambda表达式里只是通过对象名称调用一个实例方法,并且“—>”前后参数的形式一致,就可以使用实例方法引用。

代码4:演示了实例引用使用场景

Student类

public class Student {
    private String name;
    private int age;
    //构造器
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public Student() {
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    //实例方法方法引用
    public  int compare(Student o1, Student o2){
        return o1.getAge() - o2.getAge();
    }
}

Test类

import java.util.Arrays;
public class Testt  {
    public static void main(String[] args) {
        Student []s = new Student[5];
        s[0] = new Student("张三", 18);
        s[1] = new Student("李四", 19);
        s[2] = new Student("张三", 50);
        s[3] = new Student("李白", 5);
        s[4] = new Student("王五", 10);
        System.out.println("-------排序前:-------");
        print(s);
        Student t = new Student();
        //实例方法引用:对象名::实例方法名
        //前提:->前后参数形式一致,才能使用实例方法引用
        Arrays.sort(s, t::compare);
        System.out.println("-------排序后:-------");
        print(s);
    }
    //打印姓名和年龄
    public static void print(Student []s){
        for (int i = 0; i < s.length; i++){
            System.out.println(s[i]);
        }
    }
}
/*
输出结果:
-------排序前:-------
Student{name='张三', age=18}
Student{name='李四', age=19}
Student{name='张三', age=50}
Student{name='李白', age=5}
Student{name='王五', age=10}
-------排序后:-------
Student{name='李白', age=5}
Student{name='王五', age=10}
Student{name='张三', age=18}
Student{name='李四', age=19}
Student{name='张三', age=50}
 */

3、特定类型方法的引用

语法

特定类型的名称::方法

使用场景

        如果某个Lambda表达式里只是调用了一个特定类型的实例方法,并且前面参数列表中的第一个参数是作为方法主调,后面的所有参数都是作为该实例方法的入参的,则此时就可以使用特定类型的方法引用。

代码5:演示特定方法引用的使用场景。

Test类

import java.util.Arrays;
import java.util.Comparator;
public class Test {
    public static void main(String[] args) {
        //给英语名称排序
        String[] name = {"Tom", "Jerry", "Bobi", "曹操", "Mike","angela","Dlei","Jack","Andy","cao"};
        System.out.println("排序前:" + Arrays.toString(name));
        //把这个数组进行排序:
//        Arrays.sort(name);
//        System.out.println(Arrays.toString(name));
        //要求,忽略大小写进行排序(Java官方默认是按照ASCII码进行排序的)所以我们的要求官方默认搞不懂,
        // 需要我们自定义排序规则
//        Arrays.sort(name, new Comparator<String>() {
//            @Override
//            public int compare(String o1, String o2) {
//                return o1.compareToIgnoreCase(o2); //java已经为我们提供了字符串按照首字母忽略大小写比较方法:compareToIgnoreCase
//            }
//        });
        //Lambda简化
//        Arrays.sort(name, (o1, o2)->o1.compareToIgnoreCase(o2));
        //特定类型方法引用:类型名::方法名
        Arrays.sort(name, String::compareToIgnoreCase);
        System.out.println("排序后:" + Arrays.toString(name));
        Arrays.sort(name, String::compareToIgnoreCase);
    }
}
/*
输出结果:
排序前:[Tom, Jerry, Bobi, 曹操, Mike, angela, Dlei, Jack, Andy, cao]
排序后:[Andy, angela, Bobi, cao, Dlei, Jack, Jerry, Mike, Tom, 曹操]
 */

4、构造器引用

        构造器引用(Constructor Reference) 是一种特殊的语法,用于引用一个类的构造器,并将其作为函数式接口的实例。它允许你将“创建对象”这个行为当作一个函数来传递,是 Lambda 表达式的简洁替代。

语法:

类名::new

使用场景

        如果某个Lambda表达式里只是在创建对象,并且“—>”前后参数情况一致,就可以使用构造器引用。

代码6:理解构造器引用

Test类:

public class Test {
    public static void main(String[] args) {
//        CarFactory cf = new CarFactory() {
//            @Override
//            public Car getCar(String name) {
//                return new Car(name);
//            }
//        };
        //创建对象
//        Car c = cf.getCar("法拉利");
        //简化
//        CarFactory cf = name-> new Car(name);
        //用构造器引用简化
        CarFactory cf = Car::new;
        Car c = cf.getCar("法拉利");
        System.out.println(c);
    }
}
interface CarFactory{
    Car getCar(String name); //接口中的抽象方法,返回值类型为Car
}
class Car{
    private String name;
    public Car(String name) {
        this.name = name;
    }
    public Car(){}
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return this.name;
    }
    //重新toString
    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                '}';
    }
}
/*
输出结果:
Car{name='法拉利'}
 */

到此这篇关于Java中的函数式编程Lambda、方法引用详解的文章就介绍到这了,更多相关java函数式编程内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • IntelliJ IDEA 安装 Grep Console插件 自定义控制台输出多颜色格式功能

    IntelliJ IDEA 安装 Grep Console插件 自定义控制台输出多颜色格式功能

    由于Intellij idea不支持显示ascii颜色,grep-console插件能很好的解决这个问题,下面就以开发JavaEE项目中,结合Log4j配置多颜色日志输出功能,感兴趣的朋友一起看看吧
    2020-05-05
  • 深入理解jvm启动参数

    深入理解jvm启动参数

    JVM的启动参数是在启动JVM时可以设置的一些命令行参数,本文详细的介绍了深入理解jvm启动参数,具有一定的参考价值,感兴趣的可以了解一下
    2023-08-08
  • springboot中用fastjson处理返回值为null的属性值

    springboot中用fastjson处理返回值为null的属性值

    在本篇文章里小编给大家整理的是一篇关于springboot中用fastjson处理返回值问题详解内容,需要的朋友们参考下。
    2020-03-03
  • Java实现PIFrame窗体效果的示例代码

    Java实现PIFrame窗体效果的示例代码

    在很多现代应用中,常常需要使用个性化的窗体外观,摆脱传统窗口边框的限制,无边框、透明、圆角和阴影效果使得窗体显得更轻巧、更具视觉吸引力,同时允许用户自由拖拽和停靠窗体,所以本文给大家介绍了如何使用Java实现PIFrame窗体效果,需要的朋友可以参考下
    2025-03-03
  • Java实现多线程中的静态代理模式

    Java实现多线程中的静态代理模式

    静态代理属于设计模式中的代理模式。这篇文章主要介绍了Java实现多线程中的静态代理模式,详细的介绍了静态代理的使用,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05
  • Java中Map实现线程安全的3种方式

    Java中Map实现线程安全的3种方式

    本文主要介绍了Java中Map实现线程安全的3种方式,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • Java通过百度API实现图片车牌号识别

    Java通过百度API实现图片车牌号识别

    这段时间做项目需要用java程序进行车牌识别,因此尝试做了下这个程序,本代码功能是通过调用百度API实现的,感兴趣的可以了解一下
    2021-06-06
  • springboot集成测试最小化依赖实践示例

    springboot集成测试最小化依赖实践示例

    这篇文章主要为大家介绍了springboot集成测试最小化依赖实践示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-06-06
  • 基于JPA的Repository使用详解

    基于JPA的Repository使用详解

    这篇文章主要介绍了JPA的Repository使用详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • Spring boot actuator端点启用和暴露操作

    Spring boot actuator端点启用和暴露操作

    这篇文章主要介绍了Spring boot actuator端点启用和暴露操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07

最新评论