函数式编程

作者: 5fafe9a996b9 | 来源:发表于2019-07-24 15:27 被阅读0次

    函数式编程之前我们关注的往往是某一类对象应该具有什么样的属性,当然这也是面向对象的核心--对数据进行抽象。但似乎在某种场景下,更加关注某一类共有的行为描述(这似乎与之前的接口有些类似),这也就是提出函数式编程的目的。java8通过函数式接口和Lambda支持函数式编程。
    函数式编程可简单理解是把函数的实现作为函数的参数进行传递

    函数式接口

    函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。

    函数式接口可以被隐式转换为 lambda 表达式,JAVA 8 之前一般是用匿名类实现的,当然也可以显示继承实现。

    例如:定义一个函数式接口GreetingService

    @FunctionalInterface
    public interface  GreetingService {
      void sayMessage(String message);
    }
    

    函数式接口GreetingService的使用

      public static void main(String[] args) throws Exception {
        //lamda表达式实现
        hello("Andy",message -> System.out.println("Hello " + message));
        
        //匿名类实现
        hello("John",new GreetingService(){
          @Override
          public void sayMessage(String message) {
            System.out.println("你好 " + message);
          }
        });
    
        //继承实现
        GreetingService greetingService=new GreetingServiceImpl();
        hello("Peter",greetingService);
      }
      
      public static void hello(String name,GreetingService greetingService ) {
        greetingService.sayMessage(name);
      }
    

    输出结果:

    Hello Andy
    你好 John
    早上好 Peter
    

    JDK预先定义了一些函数式接口:


    image

    示例

     //Consumer<T> 消费型接口 :
     @Test
     public void test1(){
      happy(10000, (m) -> System.out.println("你们刚哥喜欢大宝剑,每次消费:" + m + "元"));
     }
     public void happy(double money, Consumer<Double> con){
      con.accept(money);
     }
    

    其他接口(一部分):


    image

    方法引用和构造器引用

    方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法。方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文。计算时,方法引用会创建函数式接口的一个实例,方法引用使用一对冒号 ::。

    当Lambda表达式中只是执行一个方法调用时,不用Lambda表达式,直接通过方法引用的形式可读性更高一些。方法引用是一种更简洁易懂的Lambda表达式。

    • 构造器引用:它的语法是Class::new,或者更一般的Class< T >:
    • 静态方法引用:它的语法是Class::static_method
    • 特定类的任意对象的方法引用:它的语法是Class::method
    • 特定对象的方法引用:它的语法是instance::method

    实例:

    public class Car {
      //Supplier是jdk1.8的接口,这里和lamda一起使用了
      public static Car create(final Supplier<Car> supplier) {
        return supplier.get();
      }
    
      public static void collide(final Car car) {
        System.out.println("Collided " + car.toString());
      }
    
      public void follow(final Car another) {
        System.out.println("Following the " + another.toString());
      }
    
      public void repair() {
        System.out.println("Repaired " + this.toString());
      }
    }
    
     public static void main(String[] args) throws Exception {
        //构造器引用Car::new
        final Car car = Car.create( Car::new );
        final List< Car > cars = Arrays.asList( car );
    
        //静态方法引用Car::collide
        cars.forEach( Car::collide );
    
        //特定类的任意对象的方法引用Car::repair
        cars.forEach( Car::repair );
    
        final Car police = Car.create( Car::new );
    
        //特定对象的方法引用police::follow
        cars.forEach( police::follow );
      }
    

    结果

    Collided cn.org.geneplus.data.CarTT.Car@f2a0b8e
    Repaired cn.org.geneplus.data.CarTT.Car@f2a0b8e
    Following the cn.org.geneplus.data.CarTT.Car@f2a0b8e
    

    Lambda表达式

    Lambda表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “->” , 该操作符被称为 Lambda 操作符或剪头操作符。它将 Lambda 分为两个部分:
    左侧: 指定了 Lambda 表达式需要的所有参数
    右侧: 指定了 Lambda 体,即 Lambda 表达式要执行的功能。

    • 语法格式一:无参,无返回值,Lambda体只需一条语句
      示例:Runnable r1 = () -> System.out.println("Hello Lambda!");
    • 语法格式二:Lambda需要一个参数
      示例:Consumer<String> con = (x) -> System.out.println(x);
    • 语法格式三:Lambda只需要一个参数时,参数的小括号可以省略
      示例:Consumer<String> con = x -> System.out.println(x);
    • 语法格式四:Lambda需要多个两个参数,并且有返回值
      示例:
    Comparator<Integer> com = (x, y) -> {
     System.out.println("函数式接口");
     return Integer.compare(x, y);
    };
    
    • 语法格式五:当Lambda体只有一条语句时,return与大括号可以省略
      示例:Comparator<Integer> com = (x, y) -> Integer.compare(x, y);

    Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出数据类型,即“类型推断”

    类型推断:Lambda 表达式中的参数类型都是由编译器推断 得出的。 Lambda 表达式中无需指定类型,程序依然可以编译,这是因为 javac 根据程序的上下文,在后台推断出了参数的类型。 Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的“类型推断”

    Lambda 是一个匿名函数,我们可以把 Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
    Lambda表达式的关键:从匿名类到 Lambda 的转换

    image

    Lambda与Lambda外变量

    Lambda表达式只能引用标记了 final的外层局部变量,这个final可以即使不显示标记也会隐式的自动标记,因此final使用了的局部变量在后续不能修改。
    在 Lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量。

    相关文章

      网友评论

        本文标题:函数式编程

        本文链接:https://www.haomeiwen.com/subject/dgixrctx.html