一、Lambda表达式
1.概述:
从JDK1.8开始为了简化使用者进行代码开发,专门提供有Lambda表达式的支持,利用此操作形式可以实现函数式的编程,对于函数式编程比较著名的语言:Scala,利用函数式的编程可以避免掉面向对象编程之中的一些繁琐的问题。 面向对象在其长期发展的过程中一直有一部分的反对者认为面向对象过于繁琐。
2.使用场景:
3.Lambda表达式的演化
案例:员工过滤年和工资
需求1:过滤出年龄是大于18岁的员工集合
需求2:过滤出薪资是大于2000的员工集合
初始版本(演化一):
import java.util.ArrayList;import java.util.List;class Staff {private String id;private String name;private int age;private int salary; //薪水public Staff() {}public Staff(String id, String name, int age, int salary) {this.id = id;this.name = name;this.age = age;this.salary = salary;}public String getId() {return id;}public void setId(String id) {this.id = id;}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 int getSalary() {return salary;}public void setSalary(int salary) {this.salary = salary;}@Overridepublic String toString() {return "Staff{" +"id='" + id + '\'' +", name='" + name + '\'' +", age=" + age +", salary=" + salary +'}';}}public class LambdaDemo1 {public static void main(String[] args) {/*需求1:过滤出年龄是大于18岁的员工集合需求2:过滤出薪资是大于2000的员工集合 *///创建一个员工ArrayList staffList = new ArrayList();staffList.add(new Staff("1001", "小明", 22, 10000));staffList.add(new Staff("1002", "小花", 17, 3000));staffList.add(new Staff("1003", "小帅", 24, 20000));staffList.add(new Staff("1004", "小李", 19, 1000));staffList.add(new Staff("1005", "小王", 16, 500));System.out.println("==================需求1:过滤出年龄是大于18岁的员工集合=======================");List staffRes1 = filterStaffWithAge(staffList);for (Staff staff : staffRes1) {System.out.println(staff);}System.out.println("==================需求2:过滤出薪资是大于2000的员工集合=======================");List staffRes2 = filterStaffWithSalary(staffList);for (Staff staff : staffRes2) {System.out.println(staff);}}public static List filterStaffWithAge(ArrayList staffList) {ArrayList staffArrayList = new ArrayList();for (Staff staff : staffList) {if (staff.getAge() > 18) {staffArrayList.add(staff);}}return staffArrayList;}public static List filterStaffWithSalary(ArrayList staffList) {ArrayList staffArrayList = new ArrayList();for (Staff staff : staffList) {if (staff.getSalary() > 2000) {staffArrayList.add(staff);}}return staffArrayList;}}
演化二:
两个方法的逻辑是一样的,减少方法,将不同需求写在接口中,把接口的具体实现子类当做参数传入方法,在一个方法中完成改写。
import java.util.ArrayList;import java.util.List;interface FilterStaff {boolean filterStaffWithAny(Staff staff);}class FilterStaffWithAge implements FilterStaff {@Overridepublic boolean filterStaffWithAny(Staff staff) {return staff.getAge() > 18;}}class FilterStaffWithSalary implements FilterStaff {@Overridepublic boolean filterStaffWithAny(Staff staff) {return staff.getSalary() > 2000;}}public class lambdaDemo2 {public static void main(String[] args) {//创建一个员工ArrayList staffList = new ArrayList();staffList.add(new Staff("1001", "小明", 22, 10000));staffList.add(new Staff("1002", "小花", 17, 3000));staffList.add(new Staff("1003", "小帅", 24, 20000));staffList.add(new Staff("1004", "小李", 19, 1000));staffList.add(new Staff("1005", "小王", 16, 500));System.out.println("==================需求1:过滤出年龄是大于18岁的员工集合=======================");List staffRes1 = filterStaff(staffList, new FilterStaffWithAge());for (Staff staff : staffRes1) {System.out.println(staff);}System.out.println("==================需求2:过滤出薪资是大于2000的员工集合=======================");List staffRes2 = filterStaff(staffList, new FilterStaffWithSalary());for (Staff staff : staffRes2) {System.out.println(staff);}}public static List filterStaff(ArrayList staffList, FilterStaff filterStaff) {ArrayList staffArrayList = new ArrayList();for (Staff staff : staffList) {if (filterStaff.filterStaffWithAny(staff)) {staffArrayList.add(staff);}}return staffArrayList;}}
演化三:
因为是接口的实现,所以可以用匿名内部类改写
import java.util.ArrayList;import java.util.List;public class lambdaDemo3 {public static void main(String[] args) {//创建一个员工ArrayList staffList = new ArrayList();staffList.add(new Staff("1001", "小明", 22, 10000));staffList.add(new Staff("1002", "小花", 17, 3000));staffList.add(new Staff("1003", "小帅", 24, 20000));staffList.add(new Staff("1004", "小李", 19, 1000));staffList.add(new Staff("1005", "小王", 16, 500));System.out.println("==================需求1:过滤出年龄是大于18岁的员工集合=======================");//使用匿名内部类的方式传参List staffRes1 = filterStaff(staffList, new FilterStaff() {@Overridepublic boolean filterStaffWithAny(Staff staff) {return staff.getAge() > 18;}});for (Staff staff : staffRes1) {System.out.println(staff);}System.out.println("==================需求2:过滤出薪资是大于2000的员工集合=======================");List staffRes2 = filterStaff(staffList, new FilterStaff() {@Overridepublic boolean filterStaffWithAny(Staff staff) {return staff.getSalary() > 2000;}});for (Staff staff : staffRes2) {System.out.println(staff);}}public static List filterStaff(ArrayList staffList, FilterStaff filterStaff) {ArrayList staffArrayList = new ArrayList();for (Staff staff : staffList) {if (filterStaff.filterStaffWithAny(staff)) {staffArrayList.add(staff);}}return staffArrayList;}}
最终版本(演化四):
使用lambda表达式改写
import java.util.ArrayList;import java.util.List;public class lambdaDemo4 {public static void main(String[] args) {//创建一个员工ArrayList staffList = new ArrayList();staffList.add(new Staff("1001", "小明", 22, 10000));staffList.add(new Staff("1002", "小花", 17, 3000));staffList.add(new Staff("1003", "小帅", 24, 20000));staffList.add(new Staff("1004", "小李", 19, 1000));staffList.add(new Staff("1005", "小王", 16, 500));System.out.println("==================需求1:过滤出年龄是大于18岁的员工集合=======================");//使用匿名内部类的方式传参//List staffRes1 = filterStaff(staffList, new FilterStaff() {//@Override//public boolean filterStaffWithAny(Staff staff) {//return staff.getAge() > 18;//}//});/** * e -> e.getAge() > 18 * * e:表示的就是一个Staff员工对象 * e.getAge() > 18 : 表示的是接口的实现逻辑 * */List staffRes1 = filterStaff(staffList, e -> e.getAge() > 18);for (Staff staff : staffRes1) {System.out.println(staff);}System.out.println("==================需求2:过滤出薪资是大于2000的员工集合=======================");//List staffRes2 = filterStaff(staffList, new FilterStaff() {//@Override//public boolean filterStaffWithAny(Staff staff) {//return staff.getSalary() > 2000;//}//});List staffRes2 = filterStaff(staffList, e -> e.getSalary() > 2000);for (Staff staff : staffRes2) {System.out.println(staff);}}public static List filterStaff(ArrayList staffList, FilterStaff filterStaff) {ArrayList staffArrayList = new ArrayList();for (Staff staff : staffList) {if (filterStaff.filterStaffWithAny(staff)) {staffArrayList.add(staff);}}return staffArrayList;}}
4.Lambda表达式基本语法
5.分类
(1)无参数,无返回值
/*1. 无参数,无返回值 */interface Inter {void fun1();}public class lambdaDemo5 {public static void main(String[] args) {show(() -> System.out.println("hello world"));}public static void show(Inter inter) {inter.fun1();}}
(2)有一个参数,无返回值
/*有一个参数,无返回值 */interface Inter1 {void fun1(String s);}public class lambdaDemo6 {public static void main(String[] args) {show("加油", e -> System.out.println("好好学习,天天向上" + e));}public static void show(String s, Inter1 inter) {inter.fun1(s);}}
6.Lambda表达式注意事项
(1)当接口的参数个数只有一个的适合,改写Lambda表达式的时候,左边小括号可以省略
(2)当接口的参数大于等于2个的时候,改写Lambda表达式的时候,左边小括号不可以省略
(3)当接口的实现逻辑大于等于2行的话,改写Lambda表达式的时候,右边大括号不能省略
(4)当接口的方法有返回值类型的时候,写Lambda表达式的时候,右边要有return
演示:
import java.util.ArrayList;import java.util.Arrays;import java.util.List;/*若只有一个参数,小括号可以省略不写 */@FunctionalInterface //这个注解是可选的,它可以确保接口仅包含一个抽象方法interface Inter5 {void fun1(int n);}/*有两个以上的参数, 无返回值的 */interface Inter6 {void fun1(int a, int b);}/*有若干个参数,并且方法有返回值 */interface Inter7 {List fun1(String s1, String s2);}/*有若干个参数,并且方法有返回值 */interface Inter8 {String fun1(String s1, String s2);}public class LambdaDemo7 {public static void main(String[] args) {//需求:接口中的逻辑是直接输出n的值//show1(10, (e) -> System.out.println(e));//TODO:结论1:当接口的参数个数只有一个的适合,改写Lambda表达式的时候,左边小括号可以省略show1(10, e -> System.out.println(e));//需求:接口中的逻辑求两个数相乘的输出//TODO:结论2:当接口的参数大于等于2个的时候,改写Lambda表达式的时候,左边小括号不可以省略show2(3, 4, (e1, e2) -> System.out.println(e1 * e2));//需求:调用show1方法,要求对传入的数值进行字符串拼接,转字节数组,将字节数组以字符串的形式输出//TODO:结论3:当接口的实现逻辑大于等于2行的话,改写Lambda表达式的时候,右边大括号不能省略show1(10, e -> {String s = e + ":数加";byte[] bytes = s.getBytes();System.out.println(Arrays.toString(bytes));});//需求:将两个字符串封装到一个集合中,返回//TODO:结论4:当接口的方法有返回值类型的时候,写Lambda表达式的时候,右边要有returnList list1 = show3("hello", "world", (a, b) -> {ArrayList list = new ArrayList();list.add(a);list.add(a);return list;});System.out.println(list1);//需求:将两个字符串进行拼接操作,返回//TODO:结论5:当接口的方法有返回值类型的时候,并且改写写Lambda表达式的时候,右边语句体只有一行语句作为返回值,那么可以省略returnString s = show4("hello", "world", (a, b) -> a + b);System.out.println(s);}public static String show4(String s1, String s2, Inter8 inter8) {return inter8.fun1(s1, s2);}public static List show3(String s1, String s2, Inter7 inter7) {return inter7.fun1(s1, s2);}public static void show1(int i, Inter5 inter5) {inter5.fun1(i);}public static void show2(int a, int b, Inter6 inter6) {inter6.fun1(a, b);}}
7.函数式接口
(1)概述:
(2)分类
Predicate 断言型接口
演示:
package com.shujia.day19.jiekou;import java.util.ArrayList;import java.util.List;import java.util.function.Predicate;public class Demo1 {public static void main(String[] args) {//创建一个员工ArrayList staffList = new ArrayList();staffList.add(new Staff("1001", "小明", 22, 10000));staffList.add(new Staff("1002", "小花", 17, 3000));staffList.add(new Staff("1003", "小帅", 24, 20000));staffList.add(new Staff("1004", "小李", 19, 1000));staffList.add(new Staff("1005", "小王", 16, 500));System.out.println("==================需求1:过滤出年龄是大于18岁的员工集合=======================");List staffRes1 = filterStaff(staffList, e -> e.getAge() > 18);for (Staff staff : staffRes1) {System.out.println(staff);}System.out.println("==================需求2:过滤出薪资是大于2000的员工集合=======================");List staffRes2 = filterStaff(staffList, e -> e.getSalary() > 2000);for (Staff staff : staffRes2) {System.out.println(staff);}}public static List filterStaff(ArrayList staffList, Predicate predicate) {ArrayList staffArrayList = new ArrayList();for (Staff staff : staffList) {if (predicate.test(staff)) {staffArrayList.add(staff);}}return staffArrayList;}}
Function 函数型接口
演示:
import java.util.function.Function;/*Function 函数型接口@FunctionalInterfacepublic interface Function {R apply(T t);} */public class Demo2 {public static void main(String[] args) {String s = show("你好", e -> "我说:" + e);System.out.println(s);}public static String show(String s, Function function) {return function.apply(s);}}
Supplier 供给型接口
演示:
import java.util.ArrayList;import java.util.List;import java.util.function.Supplier;/*供给型接口@FunctionalInterfacepublic interface Supplier {T get();}随机生成10个1-100的数据到集合返回 */public class Demo3 {public static void main(String[] args) {List integerList = getNumber(() -> (int) (Math.random() * 100 + 1));for (Integer i : integerList) {System.out.println(i);}}public static List getNumber(Supplier supplier) {ArrayList arrayList = new ArrayList();for (int i = 1; i <= 10; i++) {Integer n = supplier.get();arrayList.add(n);}return arrayList;}}
Consumer 消费型接口
演示:
import java.util.function.Consumer;/*消费型接口@FunctionalInterfacepublic interface Consumer {void accept(T t);} */public class Demo4 {public static void main(String[] args) {show(10,e-> System.out.println(e));}public static void show(int i, Consumer consumer) {consumer.accept(i);}}
8.Lambda用法再简洁之方法引用
(1)对象的引用 :: 实例方法名
(2)类 :: 静态方法名
(3)类 :: 实例方法名
(4)构造方法引用 ClassName::new
(5)数组引用
(1)~(5)演示:
import java.util.Arrays;import java.util.function.BiConsumer;import java.util.function.Function;class Student {private String name;public Student() {}public Student(String name) {this.name = name;}public void setName(String name) {this.name = name;}public String getName() {return name;}public void show(String s1, String s2) {System.out.println(s1 + "--" + s2);}public void show2(String s1, String s2) {System.out.println(s1 + "##" + s2);}public static void show3(String s1, String s2) {System.out.println(s1 + "@@" + s2);}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +'}';}}class JiaHua {public static void main(String[] args) {Student student = new Student();System.out.println(student.getName());//fun("张三", "18", (a, b) -> student.show(a, b));//TODO: 改写1:当lambda表达式中右边的对象.方法(参数),其中的参数与左边的参数一致的时候,可以进行改写成 对象名::方法名fun("张三", "18", student::show2);//TODO: 改写2:当lambda表达式中右边的类名.静态方法(参数),其中的参数与左边的参数一致的时候,可以进行改写成 类名::静态方法名//fun("李四", "19", (a, b) -> Student.show3(a, b));fun("李四", "19", Student::show3);//TODO: 改写3:当lambda表达式中右边的变量1.方法(变量2,[变量3,..]),右边的逻辑是将左边从第二个变量开始,都作为第一个变量的方法参数的时候,可以进行改写成 类名::方法名//fun2(student, "尚平", (s, n) -> s.setName(n));fun2(student, "尚平", Student::setName);System.out.println(student.getName());//TODO: 改写4:当lambda表达式中右边的new 类名(变量1,..), 其中变量是左边的变量 可以进行改写成 类名::new//Student student1 = fun3("小虎", e -> new Student(e));Student student1 = fun3("小虎", Student::new);System.out.println(student1);//TODO: 改写5:当lambda表达式中右边的new 数据类型[变量], 其中变量是左边的变量 可以进行改写成 数据类型[]::new//int[] ints = fun4(5, e -> new int[e]);int[] ints = fun4(5, int[]::new);System.out.println(Arrays.toString(ints));}public static int[] fun4(int number, Function function) {return function.apply(number);}public static Student fun3(String name, Function function) {return function.apply(name);}public static void fun2(Student student, String name, BiConsumer biConsumer) {biConsumer.accept(student, name);}public static void fun(String a, String b, BiConsumer biConsumer) {biConsumer.accept(a, b);}}
(6)注意:
二.枚举
1.概述:
枚举类型是Java中一种用于统一管理有限的常量数据的数据类型。它将常量设置为对象,提高了代码的可读性和简洁性。通过使用枚举类型,可以在代码中更方便地读取和使用常量。
2.JDK1.5之前使用枚举
演示:
/*JDK1.5之前使用枚举 */public class MeiJuDemo1 {public static void main(String[] args) {Season spring = Season.SPRING;System.out.println(spring);}}//在JDK1.5之前,人们去编写一个枚举类的实现class Season {//1. 创建枚举类的属性(成员变量),必须是作为私有常量出现private String name;private String info;//2. 必须将构造方法私有化,这是为了保证类的对象是有限个的目的private Season(String name, String info) {this.name = name;this.info = info;}//3. 提供公共的静态的final方法给外界获取枚举类中多个对象public static final Season SPRING = new Season("春天", "春暖花开");public static final Season SUMMER = new Season("夏天", "夏日炎炎");public static final Season AUTUMN = new Season("秋天", "秋高气爽");public static final Season WINTER = new Season("冬天", "银装素裹");//4. 提供公共的获取属性的方法public String getName() {return name;}public String getInfo() {return info;}//5. 重写toString()方法@Overridepublic String toString() {return "Season{" +"name='" + name + '\'' +", info='" + info + '\'' +'}';}}
3.JDK1.5之后使用枚举
演示:
/*JDK1.5之后编写枚举类的方式 */public class MeiJuDemo2 {public static void main(String[] args) {Season2 spring = Season2.SPRING;spring.fun1();Season2 winter = Season2.WINTER;winter.fun1();}}interface Inter{void fun1();}//java提供了一个关键字代替class, enum//枚举类也可以实现接口enum Season2 implements Inter{// 提供公共的静态的final方法给外界获取枚举类中多个对象//对象必须是作为枚举类中的第一个部分//SPRING("春天","春暖花开"),//等同于public static final Season SPRING = new Season("春天","春暖花开");//SUMMER("夏天","夏日炎炎"),//AUTUMN("秋天","秋高气爽"),//WINTER("冬天","银装素裹");//如果枚举类实现了一个接口,针对不同的有限个对象,自己可以有着不同的实现SPRING("春天","春暖花开"){@Overridepublic void fun1() {System.out.println("好好学习,天天向上!");}},SUMMER("夏天","夏日炎炎"){@Overridepublic void fun1() {System.out.println("游泳");}},AUTUMN("秋天","秋高气爽"){@Overridepublic void fun1() {System.out.println("吃水果");}},WINTER("冬天","银装素裹"){@Overridepublic void fun1() {System.out.println("堆雪人");}};//1. 创建枚举类的属性(成员变量),必须是作为私有常量出现private String name;private String info;//2. 必须将构造方法私有化,这是为了保证类的对象是有限个的目的private Season2(String name,String info){this.name = name;this.info = info;}//3. 提供公共的获取属性的方法public String getName() {return name;}public String getInfo() {return info;}//4. 重写toString()方法@Overridepublic String toString() {return "Season{" +"name='" + name + '\'' +", info='" + info + '\'' +'}';}}