Java8 学习笔记(一) —— Lambda 表达式 与 函数式接口

    技术2022-07-10  126

    先来一段传统的匿名内部类调用程序

    //定义一个数学接口 public interface Maths { //定义一个计算的接口方法 int calc(int a, int b); } //测试类 public class MathsTester { //定义一个打印计算结果的方法 public static void printCalcResult(int a,int b,Maths maths){ System.out.println(maths.calc(a, b)); } } //传统的匿名内部类使用方法 public static void main(String[] args) { //定义两个数 int a = 10; int b = 5; //两个数相加; MathsTester.printCalcResult(a, b, new Maths() { @Override public int calc(int a, int b) { return a + b; } }); //两个数相减; MathsTester.printCalcResult(a, b, new Maths() { @Override public int calc(int a, int b) { return a * b; } }); }

    使用Lambda表达式后

    public static void main(String[] args) { //定义两个数 int a = 10; int b = 5; //使用lambda表达式定义4个接口的实现类,(num1, num2):括号中的参数不能与外面的变量a和b重名 Maths add = (num1, num2) -> num1 + num2; //加 Maths sub = (num1, num2) -> num1 + num2; //减 //打印计算结果 MathsTester.printCalcResult(a, b, add); MathsTester.printCalcResult(a, b, sub); //简单的写法 MathsTester.printCalcResult(a, b, (num1, num2) -> num1 * num2); MathsTester.printCalcResult(a, b, (num1, num2) -> num1 / num2); //先判断,在选择如何计算,有多行语句时,要使用花括号{} MathsTester.printCalcResult(a, b, (num1, num2) -> { if (num1 > num2) { return num1 - num2; } else { return num1 + num2; } }); //直接调用接口方法 System.out.println(add.calc(a, b)); System.out.println(add.calc(a, b)); //无参数lambda表达式:() -> xxx //仅当接口的方法有且仅有一个抽象方法时,才能使用lambda表达式 }

    函数式接口

    函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。函数式接口可以被隐式转换为 lambda 表达式

    //使用注解定义该接口是一个函数式接口,也可以不加注解,只要遵循函数式接口的定义就可以 了,使用注解java编译器会自动识别错误 @FunctionalInterface public interface Hello { //抽象方法有且只有一个 void hello(); //默认方法,jdk8以前是不允许在接口中的方法有方法体的,可以定义多个默认方法 default void hi(){ System.out.println("hi.........."); } default void o(){ System.out.println("o..........."); } //可以定义静态方法 static void he(){ System.out.println("he.........."); } } //接口实现类 public class HelloImpl implements Hello { //接口抽象方法实现 @Override public void hello() { // TODO Auto-generated method stub } //可以重写父接口的默认方法,也可以不重写,Hello.o()方法,我们就没重写 @Override public void hi() { Hello.super.hi(); //调用父接口的实现 System.out.println("..........hi"); } public static void main(String[] args) { //常规接口实例化 Hello hello = new HelloImpl(); hello.hi(); //lambda表达式实例化接口 Hello _hello = () -> System.out.println("ho......"); _hello.hello(); _hello.o(); //调用父接口的静态方法 Hello.he(); } } //当MyClass和Myfun(default方法)都存在相同方法时,SubClass优先使用MyClass的方法 public class SubClass extends MyClass implements Myfun { } //当Myfun1和Myfun2都存在相同方法时(default方法),SubClass必须指定重写谁的方法 public class SubClass implements Myfun1,Myfun2 { }

     

    内置的函数式接口

    java.util.function 包下含了很多函数式接口,这里我们主要讲解四个核心接口,其他接口依葫画瓢

    @FunctionalInterface public interface Consumer<T> { void accept(T t); //表示接受单个输入参数并且不返回结果的操作 ...... } @FunctionalInterface public interface Supplier<T> { T get(); //获得结果 } @FunctionalInterface public interface Function<T, R> { R apply(T t); //输入一个参数,返回一个结果R ...... } @FunctionalInterface public interface Predicate<T> { boolean test(T t); //输入一个参数,返回布尔值 ...... } public class Tester { //Consumer<T> public void happy(double money, Consumer<Double> consumer){ consumer.accept(money); } @Test public void testHappy(){ happy(1000, (m) -> System.out.println("这次去happy,一共消费了"+m+"元")); } //Supplier<T> public List<String> fillList(int size,Supplier<String> supplier){ List<String> list = new ArrayList<String>(); for (int i = 0; i < size; i++) { list.add(supplier.get()); } return list; } @Test public void testFillList(){ System.out.println(fillList(10, () -> Math.random() + "")); } //Function<T, R> public String strHandler(String str, Function<String, String> fun){ return fun.apply(str); } @Test public void testStrHandler(){ System.out.println(strHandler("\t\t\t清除两端空格 ", (str) -> str.trim())); } //Predicate<T> public List<String> filterStr(List<String> list, Predicate<String> pre){ List<String> newList = new ArrayList<>(); for (int i = 0; i < list.size(); i++) { if(pre.test(list.get(i))){ newList.add(list.get(i)); } } return newList; } @Test public void testFilterStr(){ List<String> list = new ArrayList<>(Arrays.asList("Hello", "atguigu", "Lambda", "www", "ok")); System.out.println(filterStr(list, (s) -> s.length() > 3)); } }

    其他函数式接口描述:https://www.runoob.com/java/java8-functional-interfaces.html

    方法引用

    方法引用比lambda表达式代码量更简洁

    public static void main(String[] args) { //lambda表达式的写法 Consumer<String> consumer = (str) -> System.out.println(str); //方法引用的写法,使用两个英文冒号,后面跟方法名 //要求println方法的入参和返回值和Consumer接口的方法一直才能这样使用 Consumer<String> _consumer = System.out::println; //其他示例 Supplier<Double> supplier = () -> Math.random(); Supplier<Double> _supplier = Math::random; //使用静态方法 //使用第一个参数的方法进行调用 BiPredicate<String, String> bp = (x, y) -> x.equals(y); BiPredicate<String, String> bp2 = String::equals; System.out.println(bp.test("abcde", "abcde")); //比较两个Employee类 BiPredicate<Employee, Employee> biPredicate = (e1,e2) -> e1.compare(e2); //第一个入参是e1,返回值时使用e1.compare返回的,这种情况就可以简写为e1::xxx BiPredicate<Employee, Employee> bp3 = Employee::compare; System.out.println(bp3.test(new Employee("zhangsan"), new Employee("lisi"))); //构造方法引用 Supplier<Employee> supplier3 = Employee::new; Employee employee = supplier3.get(); //有参构造方法引用 Function<String, Employee> function = Employee::new; Employee employee2 = function.apply("wangwu"); //数组引用 Function<Integer, String[]> fun = (size) -> new String[size]; Function<Integer, Employee[]> fun2 = Employee[] :: new; } public class Employee { private int id; private String name; private int age; private double salary; public Employee() { } public Employee(String name) { this.name = name; } public boolean compare(Employee employee){ return this.getName().equals(employee.getName()); } }

     

    Processed: 0.016, SQL: 9