欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > [Java]函数式编程

[Java]函数式编程

2025/2/7 1:16:10 来源:https://blog.csdn.net/CSDN20221005/article/details/145449838  浏览:    关键词:[Java]函数式编程

Lambda函数

JDK8新增的语法形式, 使用Lambda函数替代某些匿名内部类对象,从而让程序代码更简洁,可读性更好。

基本使用

lambda表达式只能简化函数式接口的匿名内部类写法

// 1.定义抽象类
abstract class Animal {public abstract void crt();
}public class LambdaDome {public staitc void main(String[] args) {// 2.使用匿名内部类, 创建抽象类的子类对象Animal a = new Animal() {@Overridepublic void cry() {sout("猫喵喵的叫")}}// 3. 错误示范, 代码报错// lambda表达式并不能简写所有匿名内部类的写法Animal a = () -> {sout("猫喵喵的叫")}a.cry(); // 猫喵喵的叫}
}
// 1.定义函数式接口
// 定义: 有且只有一个抽象方法的接口称为函数式接口
// 注解: 约束函数式接口的注解, 不符合要求会报错
@FunctionalInterface
interface Swim {void swimming();
}public class LambdaDome {public staitc void main(String[] args) {// 2.使用匿名内部类, 创建接口类的子类对象Swim a = new Swim() {@Overridepublic void swimming() {sout("老师狗爬式游泳")}}// 3. 使用lambda表达式简化匿名内部类写法Swim a = () -> {sout("老师狗爬式游泳")}a.swimming(); // 老师狗爬式游泳}
}
  1. 什么是函数式接口? 有且仅有一个抽象方法的接口。
  2. 大部分函数式接口,上面都会有 @Functionallnterface 注解, 用于约束当前接口必须是函数式接口。

简化规则

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

  1. 参数类型全部可以省略不写。
  1. 如果只有一个参数, “()”也可以省略,但多个参数不能省略
  2. 如果Lambda表达式中只有一行代码,大括号可以不写,同时要省略分号“;”
  3. 如果这行代码是return语句,也必须去掉return。
public class Test {public static void main(String[] args) {// 需求: 创建一个登录窗口,窗口上有一个登录按钮JFrame win = new JFrame("登录窗口");win.setSize(300, 200);win.setLocationRelativeTo(null); // 居中展示win.setDefaultCloseOperaion(JFrame.EXIT_ON_CLOSE);JPanel penel new JPanel();win.add(penel);JButton btn = new JButton("登录");// 2.匿名内部类: 快速创建对象, 传给方法// btn.addActionListener(new ActionListener{//       public void actionPerfirmed(ActionEvent e) {//          sout("按钮点击了")//       }// });// 3. 使用lambda表达式的规则简化语法btn.addActionListener(e -> sout("按钮点击了"));win.setVisible(true);}
}
public class Test {public static void main(String[] args) {// 需求: 完成数组排序, 加深匿名内部类的使用// 1. 准备数组,存放学生对象student[] students = new student[4];students[0] = new Student( name:"殷素素",age:35,height:171.5,sex:'女');students[1] = new Student( name:"杨幂",age:28,height: 168.5,sex:'女');students[2] = new student( name:"张无忌"age:25,height:181.5,sex:'男');students[3] = new student( name:"刘亦菲",age: 36,height: 168,sex:'女');// 2.使用数组的API, 对数组按照对象的年龄升序排序// Arrays.sort(students, new Comparator<Student>() {//     @Override//     public int compare(Student o1, Student o2) {//         // 按对象年龄升序排序//         return o1.getAge() - o2.getAge();//         // 按对象年龄降序排序//         return o2.getAge() - o1.getAge();//     }// });//3.使用lambda表达式的规则简化语法Arrays.sort(students, (o1,o2) -> o1.getAge() - o2.getAge());// 3.遍历数组中的对象并输出for (int i = 0; i<students.length; i++) {student s = students[i];sout(s);}}
}

方法引用

进一步简化Lambda表达式, 遇到可以简化场景时使用(IDEA会提示)

静态方法引用

类名::静态方法

如果某个Lambda表达式里只是调用一个静态方法, 并且 "->"前后参数的形式一致, 就可以使用静态方法引用

public class Student {private String name;private int age;private double height;private String sex;// 提供静态方法public static int compareByAge(Student s1, Student s2) {return s1.getAge() - s2.getAge()}
}public class Test {public static void main(String[] args) {// 1. 准备数组,存放学生对象student[] students = new student[4];students[0] = new Student( name:"殷素素”,age:35,height:171.5,sex:'女');students[1] = new Student( name:"杨幂",age:28,height: 168.5,sex:'女');students[2] = new student( name:"张无忌"age:25,height:181.5,sex:'男');students[3] = new student( name:"刘亦菲",age: 36,height: 168,sex:'女');// 2.使用数组的API, 对数组按照对象的年龄升序排序// Arrays.sort(students, (o1, o2) -> o1.getAge() - o2.getAge());// 3.使用lambda表达式调用静态方法// Arrays.sort(students, (o1, o2) -> Student.compareByAge(o1, o2));// 3.使用静态方法引用进一步简化Arrays.sort(students, Student::compareByAge);// 4.遍历数组中的对象并输出for (int i = 0; i<students.length; i++) {student s = students[i];sout(s);}}
}

实例方法引用

对象名::实例方法

如果某个Lambda表达式里只是调用一个实例方法, 并且"->"前后参数的形式一致, 就可以使用实例方法引用

public class Student {private String name;private int age;private double height;private String sex;// 提供实例方法public int compareByAge(Student s1, Student s2) {return s1.getAge() - s2.getAge()}
}public class Test {public static void main(String[] args) {// 1. 准备数组,存放学生对象student[] students = new student[4];students[0] = new Student( name:"殷素素”,age:35,height:171.5,sex:'女');students[1] = new Student( name:"杨幂",age:28,height: 168.5,sex:'女');students[2] = new student( name:"张无忌"age:25,height:181.5,sex:'男');students[3] = new student( name:"刘亦菲",age: 36,height: 168,sex:'女');// 2.使用数组的API, 对数组按照对象的年龄升序排序// Arrays.sort(students, (o1, o2) -> o1.getAge() - o2.getAge());// 3.使用lambda表达式调用实例方法Student s1 = new Student();// Arrays.sort(students, (o1, o2) -> s1.compareByAge(o1,o2));// 3.使用实例方法引用进一步简化Arrays.sort(students, s1::compareByAge);// 4.遍历数组中的对象并输出for (int i = 0; i<students.length; i++) {student s = students[i];sout(s);}}
}

特定类型的方法引用

特定类的名称::方法

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

public class Demo {public static void main(String[] args) {// 需求:有一个字符申数组,里面有一些人的名字都是,请按照名字的首字母升序排序String[] names = {"Tom", "Jerry", "Bobi", "曹操", "Mike", "angela", "Dlei", "Jack", "Rose", "Andy", "caocao"};// 1.对数组排序: Arrays.sort(数组, 比较器对象)Arrays.sort(names);  // 默认就是按照首字母的编号升序排序System.out.println(Arrays.toString(names)); // [Andy, Bobi, Jack, Jerry, Mike, Rose, Tom, angela, caocao, 曹操, Dlei]// 2.需要忽略首字母的大小写进行升序排序(java官网默认是搞不定的,需要自己指定比较规则)Arrays.sort(names, new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {return o1.compareToIgnoreCase(o2); // java提供了字符串按照首字母忽略大小写比较的方法}});System.out.println(Arrays.toString(names)); // [Andy, angela, Bobi, caocao, Dlei, Jack, Jerry, Mike, Rose, Tom, 曹操]// 3.使用特定类型的方法引用简化代码Arrays.sort(names, String::compareToIgnoreCase);System.out.println(Arrays.toString(names)); // [Andy, angela, Bobi, caocao, Dlei, Jack, Jerry, Mike, Rose, Tom, 曹操]}
}

构造器引用

类名::new

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

// 汽车类
class Car {private String name;
}// 函数式接口
@FunctionalInterface
interface CarFactory {Car getCar(String name);
}public class Demo {public static void main(String[] args) {// 1.创建接口的匿名内部类对象CarFactory cf = new CarFactory() {@Overridepublic Car getCar(String name) {return new Car(name);}}// 2.使用lambda表达式简写CarFactory cf = name -> new Car(name);// 3.构造器引用进一步简化CarFactory cf = Car::new;Car c1 = cf.getCar("奔驰");System.out.println(c1); // Car(name=奔驰)}
}

Stream流

认识流

Jdk8开始新增的一套API(iava.util.stream.*),可以用于操作集合或者数组的数据

  1. 先得到集合或者数组的Stream流。
  2. 然后调用Stream流的方法对数据进行处理。
  3. 获取处理的结果。

示例代码

public class Dome {public static void main(String[] args) {// 1.认识stream流的使用// 需求: 把集合中所有以“张”开头,且是3个字的元素存储到一个新的集合ArrayList<String> list = new ArrayList<>();list.add("张无忌");list.add("周芷若");list.add("赵敏");list.add("张强");list.add("张三丰");// 2.使用传统方式完成需求List<String> newList = new ArrayList<>();for (String l : list) {if (l.startsWith("张") && l.length() == 3) {newList.add(l);}}// [张无忌, 张三丰]System.out.println(newList);// 3.使用stream流完成需求List<String> newList2 = list.stream().filter(l -> l.startsWith("张")).filter(l -> l.length() == 3).collect(Collectors.toList());// [张无忌, 张三丰]System.out.println(newList2);}
}
  1. Stream流大量的结合了Lambda的语法风格来编程,功能强大,性能高效,代码简洁,支持链式编程

获取流

1.获取集合的Stream流

public class Dome2 {public static void main(String[] args) {// 获取Stream流// 1.获取Collection集合流// 使用Collection接口提供的stream()方法获取流Collection<String> list = new ArrayList<>();Stream<String> s1 = list.stream();// 2.获取Map集合流Map<String, Integer> map = new HashMap<>();// 获取键流Stream<String> s2 = map.keySet().stream();// 获取值流Stream<Integer> s3 = map.values().stream();// 获取键值对流Stream<Map.Entry<String, Integer>> s4 = map.entrySet().stream();}
}
2.获取数组的Stream流

public class Dome2 {public static void main(String[] args) {// 获取Stream流String[] arr = {"a", "b", "c", "d"};// 3.获取数组流// 使用Stream类中的静态方法of()Stream<String> s5 = Stream.of(arr);// 使用Arrays类中的静态方法stream()Stream<String> s6 = Arrays.stream(arr);}
}

处理流

中间方法指的是调用完成后会返回新的Stream流,可以继续使用(支持链式编程),

public class Dome3 {public static void main(String[] args) {// 使用stream流的中间方法处理数据ArrayList<String> list = new ArrayList<>();list.add("张无忌");list.add("周芷若");list.add("赵敏");list.add("张强");list.add("张三丰");// 1.过滤方法list.stream().filter(s -> s.startsWith("张") && s.length() == 3).forEach(System.out::println); // 张无忌, 张三丰// 2.排序方法List<Double> scores = new ArrayList<>();scores.add(99.9);scores.add(66.1);scores.add(88.7);scores.add(66.1);scores.add(72.3);scores.add(88.7);// 默认是升序排序  66.1 72.3 88.7 99.9scores.stream().sorted().forEach(System.out::println);// 指定排序规则(降序) 99.9 88.7 72.3 66.1scores.stream().sorted((o1, o2) -> Double.compare(o2, o1)).forEach(System.out::println);// 3.截取方法,// 只要前3名 99.9 88.7 72.3scores.stream().sorted((o1, o2) -> Double.compare(o2, o1)).limit(3).forEach(System.out::println);// 跳过前2名 72.3 66.1scores.stream().sorted((o1, o2) -> Double.compare(o2, o1)).skip(2).forEach(System.out::println);// 4.去重方法 99.9 66.1 88.7 72.3// 如果自定义对象需要去重, 该对象必须重写hashCode和equals方法scores.stream().distinct().forEach(System.out::println);// 5.映射/加工方法: 把流里面的元素进行加工, 得到新的集合// 成绩是:99.9分 成绩是:66.1分 成绩是:88.7分 成绩是:66.1分 成绩是:72.3分 成绩是:88.7分scores.stream().map(s -> "成绩是:" + s + "分").forEach(System.out::println);// 6.合并流Stream<String> s1 = Stream.of("张无忌", "赵敏", "张三丰");Stream<Integer> s2 = Stream.of(11, 22, 31);Stream<Object> s3 = Stream.concat(s1, s2);System.out.println(s3.count()); // 6}
}

终结流

使用Stream是为了方便的操作集合和数组, 操作完成后把结果收集到数组或集合中, 才是最终的目的

  1. 终结流

  • 补充: Optional容器中的元素需要通过get()方法获取出来

  1. 收集流

代码示例

public class Teacher {private String name;private int age;private double salary;//... 省略构造器和get/set方法 ...@Overridepublic String toString() {return "Teacher{" +"name='" + name + '\'' +", age=" + age +", salary=" + salary +'}' + '\n';}
}
public class Dome4 {public static void main(String[] args) {// 掌握终结Stream流的方法List<Teacher> list = List.of(new Teacher("张三", 18, 5000),new Teacher("李四", 28, 6000),new Teacher("王五", 38, 7000),new Teacher("赵六", 48, 8000));// 1.遍历终结// Teacher{name='王五', age=38, salary=7000.0} Teacher{name='赵六', age=48, salary=8000.0}list.stream().filter(t -> t.getSalary() > 6000).forEach(System.out::println);// 2.获取结果数量long count = list.stream().filter(t -> t.getSalary() > 6000).count();System.out.println(count); // 2// 3.获取最大值 (根据工资)Teacher max = list.stream().max(Comparator.comparing(Teacher::getSalary)).get();System.out.println(max); // Teacher{name='赵六', age=48, salary=8000.0}// 4.获取最小值 (根据年龄)Teacher min = list.stream().min(Comparator.comparing(Teacher::getAge)).get();System.out.println(min); // Teacher{name='张三', age=18, salary=5000.0}}
}
public class Dome5 {public static void main(String[] args) {// 掌握收集Stream流的方法List<Teacher> list = List.of(new Teacher("张三", 18, 5000),new Teacher("李四", 28, 6000),new Teacher("王五", 38, 7000),new Teacher("赵六", 48, 8000));// 1. 把流收集到list集合中List<Teacher> list1 = list.stream().filter(s -> s.getName().startsWith("张")).collect(Collectors.toList());System.out.println(list1); // [Teacher{name='张三', age=18, salary=5000.0}]// 2. 把流收集到set集合中Set<Teacher> list2 = list.stream().filter(s -> s.getName().startsWith("张")).collect(Collectors.toSet());System.out.println(list2);// [Teacher{name='张三', age=18, salary=5000.0}]// 3. 把流收集到数组中Object[] list3 = list.stream().filter(s -> s.getName().startsWith("张")).toArray();System.out.println(Arrays.toString(list3)); // [Teacher{name='张三', age=18, salary=5000.0}]// 4. 把流收集到Map集合中: 键是老师的名字, 值是老师的薪水// 4.1完整写法
//        Map<String, Double> map = list.stream().collect(Collectors.toMap(new Function<Teacher, String>() {
//            @Override
//            public String apply(Teacher teacher) {
//                return teacher.getName();
//            }
//        }, new Function<Teacher, Double>() {
//            @Override
//            public Double apply(Teacher teacher) {
//                return teacher.getSalary();
//            }
//        }));// 4.2lambda简写
//        Map<String, Double> map = list.stream().
//                collect(Collectors.toMap(teacher -> teacher.getName(), teacher -> teacher.getSalary()));// 4.3方法引用简写Map<String, Double> map = list.stream().collect(Collectors.toMap(Teacher::getName, Teacher::getSalary));System.out.println(map); // {李四=6000.0, 张三=5000.0, 王五=7000.0, 赵六=8000.0}}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com