zoukankan      html  css  js  c++  java
  • JavaSE高级 -JDK1.8新特性-Lambda表达式-函数式接口

    一、Lambda表达式:
    标准格式由三个部分组成:
    一些参数
    一个箭头
    一段代码

    Lambda表达式的标准格式:
    (参数类型 参数名称)->{ 代码语句 }

    格式说明:
    小括号的语法与传统方法参数列表一致:无参数则留空,多个参数就用逗号隔开
    -> 新引入的语法格式,代表指向动作
    大括号内的语法和传统方法体的要求一致
    总结:Lambda表达式简化匿名内部类,首先要求是接口,其次是该接口只有一个抽象方法。

    无参数:
    无参数:不需要任何条件即可执行该方案
    无返回值:该方案不产生任何结果
    代码块(方法体):该方案的具体执行步骤
    同样的语义体现在Lambda中更简单:
    ()-> System.out.println("多线程执行!");

    前面的一对小括号即run方法的参数(无),代表不需要任何条件。
    中间的箭头代表将前面的参数传递给后面的代码。
    后面的输出语句是业务逻辑代码。

    有参数和返回值:
    例如:Arrays.sort()
    传统写法:
    实际上只有参数和方法体是重要的
    Lambda写法:
    // Lambda
    Arrays.sort(array, (Person a, Person b) -> {
    return a.getAge() - b.getAge();
    });

    省略格式:
    省略规则:
    在Lambda标准格式基础上,使用省略的写法规则是:
    小括号内的参数类型可省略;
    如果小括号内有且仅有一个参数,则小括号可以省略;
    如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、语句分号,必须省略return关键字。

    可推导即可省略:
    Lambda强调的是“做什么”而不是“怎么做”,所以凡是可以根据上下文推导得知的信息,都可以省略。
    //Runnable接口简化:

    1. () -> System.out.println("多线程任务执行!")

    //Comparator接口简化:
    2. Arrays.sort(array, (a, b) -> a.getAge() - b.getAge());

    //ActionListener接口简化:
    3.button.addActionListener(e -> System.out.println("按钮被点击了!"));

    Lambda的前提条件:
    Lambda的语法非常简洁,完全没有面向对象的束缚。但是使用时有几个问题需要特别注意:
    使用Lambda 必须具有接口,且要求接口中有且仅有一个抽象方法。
    无论时JDK内置的Runnable 、comparator 接口还是自定义接口,只有当接口中的抽象方法 存在且唯一时,才可以使用Lambda。
    使用Lambda必须具有上下文推断。
    也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。
    ps:有且仅有一个抽象方法的接口,称为:函数式接口。

    二、函数式接口
    1.概念:
    函数式接口(Funtional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。注解:@FuntionalInterface 可以检测接口是否是一个函数式接口。(在合作开发中,避免同事修改此接口造成错误)。
    2.函数的定义和使用
    定义一个函数式接口:
    //问候
    @FunctionalInterface
    public interface GreetingService {
    void sayMessage();
    }

    定义此函数式接口的实现类:
    public class GreetingServiceImpl implements GreetingService {
    @Override
    public void sayMessage() {
    System.out.println("say hello!");
    }
    }

    函数式接口一般作为方法的参数和返回值类型:
    public class Demo {
    //定义一个方法,参数使用函数式接口GreetingService
    public static void show(GreetingService greetingService){
    greetingService.sayMessage();
    }

    public static void main(String[] args) {
        //调用show方法,方法的参数是一个接口,所以可以传递接口的实现类
        show(new GreetingServiceImpl());
    
        //调用show方法,方法的参数是一个接口,所以可以传递接口的匿名内部类
        show(new GreetingService() {
            @Override
            public void sayMessage() {
                System.out.println("使用匿名内部类重写接口中的抽象方法");
            }
        });
    }
    

    }

    Lambda表达式的写法:
    public class Demo {
    //定义一个方法,参数使用函数式接口GreetingService
    public static void show(GreetingService greetingService){
    greetingService.sayMessage();
    }

    public static void main(String[] args) {
        //调用show方法,使用lambda表达式
        show(()->System.out.println("使用lambda重写接口中的抽象方法"));
    }
    

    }

    3.Lambda表达式的好处:
    优势:1.简化代码,更为简洁 2.延迟加载
    有些场景的代码执行后,结果不一定会被使用,从而造成性能的浪费。而Lambda表达式是延迟执行的,这正好可以作为解决方案,提升性能。

    例如:性能浪费的日志案例:
    ps: 日志可以帮助我们快速定位问题,记录程序运行中的情况,以便项目的监控和优化。
    一种典型的场景就是对参数进行有条件使用,例如对日志消息进行拼接后,在满足条件的情况下打印输出:
    public class Test {
    public static void main(String[] args) {
    String msgA = "hello";
    String msgB = "world";
    String msgC = "java";
    showLog(1, msgA + msgB + msgC);
    }

    private static void showLog(int level, String msg) {
    //当日志级别为1时,打印日志
    if (level == 1) {
    System.out.println(msg);
    }
    }
    }

    这段代码存在的问题是:无论级别是否满足要求,作为showLog方法的第二个参数,三个字符串一定会首先被拼接并传入方法内,然后才会进行级别判断。如果级别不符合要求,那么字符串的拼接操作就白做了,存在性能的浪费。

    使用Lambda 必然先定义一个函数式接口:
    @FunctionalInterface
    interface MessageBuilder{
    String buildMessage();
    }

    对showLog方法进行改造:
    public class Test {
    public static void main(String [] ags){
    String msgA = "hello";
    String msgB = "world";
    String msgC = "java";

        //lambda实现显示日志
        showLogLambda(1,()->msgA+msgB+msgC);
        
        //证明lambda表达式的延迟执行
        showLogLambda(1,()->{
            System.out.println("Lambda执行!");
            return msgA+msgB+msgC;
        });
    }
    
    private static void showLogLambda(int level,MessageBuilder builder){
        if(level==1){
            System.out.println(builder.buildMessage());
        }   
    }
    

    }

    这样一来,只有当级别满足要求的时候,才会进行三个字符串的拼接;否则三个字符串将不会拼接。

    三、常用的函数式接口:
    四大核心函数接口:
    函数式接口 参数类型 返回类型 用途
    Supplier接口,供给型接口 无 T 返回的类型为T的对象,T get()
    Consumer 接口,消费型接口 T void 对类型为T的对象应用操作,void accept(T t)
    Function<T,R> 函数型接口 T R 根据类型T的参数获取类型R的结果,R apply(T t)
    Predicate< T>接口,断定型接口 T boolean 用于条件判断的场景,boolean test(T t)

    Supplier< T>接口: 函数式接口
    T get();
    供给型
    特点:使用其get(),可以返回一个与接口泛型一致的数据。

    Consumer< T>接口:函数式接口
    accept(T t)
    消费型
    default andThen() 默认方法
    特点:提供一个与泛型一致数据类型的参数。

    Function<T,R>接口:函数式接口
    R apply(T t)
    default andThen(Function <T f) 组合操作
    根据泛型的类型,将前者的T类型转化为R类型。

    Predicate接口:函数式接口
    boolean test(T t); 返回true、false。
    default Predicate and (Predicate<? super T> other ) 与
    default Predicate negate() 非
    default Predicate or (Predicate<? super T> other) 或
    对某种类型的数据进行判断,从而得到一个boolean值结果。

    四、方法的引用:
    方法的引用的概述:
    方法引用使得开发者可以直接引用现存的方法,Java类的构造方法或者实例对象。方法的引用和Lambda表达式配合使用,使得Java类的构造方法看起来紧凑而简洁,没有很多复杂的模板代码。

    静态方法的引用:
    引用格式:
    类名::静态方法
    简化步骤:
    定义一个静态方法,把需要简化的代码放到一个静态方法中。
    注意事项:
    被引用的方法的参数列表,要和函数式接口中的抽象方法的参数列表一致。
    如果函数式接口中的抽象方法有返回值,则被引用的方法必须也有相同返回值。
    如果函数式接口中的抽象方法没有返回值,则被引用的方法可以有返回值,也可以没有返回值。
    实例方法的引用:
    引用格式:
    对象::实例方法
    简化步骤:
    定义一个实例方法,把需要的代码放到实例方法中。
    注意事项:
    被引用的方法的参数列表,要和函数式接口中的抽象方法的参数列表一致。

    特定类型的方法引用:
    引用格式:
    特定类型::方法
    特点类型:
    String,任何类型
    注意事项:
    如果函数式接口中的抽象方法的参数列表中,第一个参数作为了后面的方法的调用者,并且
    其余参数作为后面方法的形参,那么就可以用特定类型的方法引用了。

    构造器的引用:
    引用格式:
    类名::new
    注意事项:
    函数式接口的抽象方法的形参列表和构造器的形参列表一致,抽象方法返回值类型即为构造器所属的类的类型。
    类似于 s->new Student(s) =>Student::new

  • 相关阅读:
    DNS 壓力測試
    2008IT技术精英年会数据库分论坛热点扫描
    DOS command
    说说大型高并发高负载网站的系统架构
    DNS Server &Bind的配置与使用
    IoC 容器和Dependency Injection 模式
    Inversion of Control Containers and the Dependency Injection pattern
    Windows 2003网络负载均衡的实现
    UVA 10369 Arctic Network
    UVA 10397 Connect the Campus
  • 原文地址:https://www.cnblogs.com/monkeycode/p/14070952.html
Copyright © 2011-2022 走看看