函数式接口@FunctionalInterface学习(函数编程思想)------------与匿名内部类对比

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/cszhang570221322/article/details/84656329

 在java8中

1、新推出了一个接口概念:函数式接口。

2、允许接口也可以有default方法,default方法可以方法体。

他满足以下规范:

  1. 接口有且只能有个一个抽象方法(抽象方法只有方法定义,没有方法体)
  2. 不能在接口中覆写Object类中的public方法(写了编译器也会报错)
  3. 允许有default实现方法。

如下例子是函数式接口:

package zzu.zwl.main;

/**
 * Created by zwl on 2018/11/30.
 * May god bless me
 */
@FunctionalInterface
public interface GreetingService {
    String sayMessage(String message);
    default void doSomeMoreWork1()
    {
        // Method body
    }

    default void doSomeMoreWork2()
    {
        // Method body
    }
    static void printHello(){
        System.out.println("Hello");
    }
    @Override
    String toString();  //Object中的方法,但不重写
}

而@FunctionalInterface是干什么的?

   当你添加上这个注解后,仅仅是检查是否符合函数式接口规范,而不具有其他作用,因此jdk8之前常用的匿名内部类监听器类也可以使用lambda编程,如下

//ActionListener的Java源码如下,他没有使用@FunctionalInterface注解

/*
 * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package java.awt.event;

import java.util.EventListener;

/**
 * The listener interface for receiving action events.
 * The class that is interested in processing an action event
 * implements this interface, and the object created with that
 * class is registered with a component, using the component's
 * {@code addActionListener} method. When the action event
 * occurs, that object's {@code actionPerformed} method is
 * invoked.
 *
 * @see ActionEvent
 * @see <a href="http://docs.oracle.com/javase/tutorial/uiswing/events/actionlistener.html">How to Write an Action Listener</a>
 *
 * @author Carl Quinn
 * @since 1.1
 */
public interface ActionListener extends EventListener {

    /**
     * Invoked when an action occurs.
     * 只有一个未定义方法,符合函数式接口规范。
     * @param e the event to be processed
     */
    public void actionPerformed(ActionEvent e);  


}
/**
 *下面是例子
 *  
 **/

package zzu.zwl.main;


import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;


/**
 * Created by zwl on 2018/11/30.
 * May god bless me
 */
public class Main {
    private static JButton jButton;

    public static void main(String[] args) {

      jButton.addActionListener(new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
              System.out.println(e.paramString());
          }
      });
        //也可以用lambda表达式编程,只关注输入和输出,虽然很 actionPerformed的输出为void类型。
        jButton.addActionListener(e -> System.out.println(e.paramString()));
  }
}

明白了以上代码,接下来是函数式编程与匿名内部类的对比编程。

package zzu.zwl.main;


import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;


/**
 * Created by zwl on 2018/11/30.
 * May god bless me
 */
public class Main {
    private static JButton jButton;

    public static void main(String[] args) {

      jButton.addActionListener(new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
              System.out.println(e.paramString());
          }
      });
        jButton.addActionListener(e -> System.out.println(e.paramString()));

        /**
         * 为了更好理解FunctionInterface,暂且抛开lambda不看
         * 这里不过是传统的两个步骤
         * 1、定义了一个方法,两个参数,传入一个字符串,调用接口的方法
         *
         *  这里相当于,先调用joinStr方法,传入'你好'和一个匿名内部类(匿名内部类实现了getMessage方法)
         *  代码执行顺序为先进入joinStr方法,然后执行方法体
         *  方法体是调用接口的sayMessage方法(传入的是这里的str '你好'),
         *  因此代码执行顺序为
         *  jdk8之前---1
         *  jdk8之前---2
         *  jdk8之前---3
         *  jdk8之前---4
         *  jdk8之前---5
         */
       String  msg= joinStr("你好", new GreetingService() {   //  jdk8之前---1
            @Override
            public String sayMessage(String message) {  //实现接口的方法。
                System.out.println("匿名接口"); //  jdk8之前---3
                return  message;   //  jdk8之前---4
            }
        });
        /**
         * 打印
         */
        System.out.println(msg);   //  jdk8之前---7


        /**
         * 1.接收一个message,执行一部分动作,然后如果FunctionInterface有返回值,则返回一个对应的返回值。
         *  这里用jdk8以前理解方式是 定义一个匿名内部类,相当于如下形式,所以代码不会执行

         GreetingService greetingService = new GreetingService() {
                @Override
                public String sayMessage(String message) {
                System.out.println(message);
                return message + "i";
        }
        };
         *
         */
        GreetingService greetingService1 = message -> {
            System.out.println(message);
            return message + "i";
        };


        /**
         *  2.本质上与1相似,但是此处是方法引用 ,相当于JDK8之前的如下形式
         *     GreetingService greetingService2 = new GreetingService() {
                @Override
                public String sayMessage(String message) {
                return Main.getInstance(message);
                }
        };
         *
         */

        GreetingService greetingService2 = Main::getInstance;
        /**
         * 这里传来传去,实际上就是"你好"-->getInstance:item了,只不过中间规范化的定义一个接口,不同的是以前用匿名内部类实现,
         * 现在不关注类,而只关注抽象方法,接口相当于约束了传入参数和返回参数,从而使用lambda表达式来书写,只关注计算过程的输入和输出,有一点点函数编程的思想。
         */
        String msg1= joinStr("你好",greetingService2);
        System.out.println(msg1);

        //3与上述过程2一致。
        GreetingService greetingService2_1 = message -> Main.getInstance(message);
        //4与上述过程2、3一致。
        GreetingService greetingService2_2 = message -> {
            return Main.getInstance(message);
        };


        String msg1_1  = joinStr("你好",greetingService2_1);
        System.out.println(msg1_1);
        String msg1_2  = joinStr("你好",greetingService2_2);
        System.out.println(msg1_2);

        System.out.println("****************************华丽分割线**********************");
        /**
         * 上面看着是不是很鸡肋,下面的例子实践后会很方便。
         */
        //这样是不是简便很多,不用定义这个匿名内部类,直接关注输入(传入参数),输出(返回值)
        String msg3 = joinStr("这个值传给旁边的message:",message -> message+"Hello,World");
        //实现具体方法的时候用多行代码。 为了复习,下面的代码再用JDK8之前的重写一遍。
        String msg4 = joinStr("这个值传给旁边的message",message -> {
            System.out.println("你好呀,函数式编程。");
            return message+"Hello,World";
        });
        String BeforeJdk8_msg4=joinStr("这个值传给旁边的message:", new GreetingService() {
            @Override
            public String sayMessage(String message) {
                System.out.println("你好呀,函数式编程。");
                return message+"Hello,World";
            }
        });
        System.out.println(msg3);
        System.out.println(msg4);
        System.out.println(BeforeJdk8_msg4);

    }

    /**
     * 简单方法
     * @param item
     * @return
     */
    public static String getInstance(String item) {
        return item + "!世界";
    }

    /**
     * 简单方法
     * @param massage
     * @return
     */
    public static String getMessage(String massage){
        return "世界,"+ massage+"!";
    }

    /**
     * 定义一个方法,两个参数
     * @param str  字符串类型
     * @param greetingService  一个传接口,调用接口里的一个方法sayMessage,很常见的方法参数类型
     * @return
     */
    public  static String joinStr(String str,GreetingService greetingService) {

        String s = greetingService.sayMessage(str); //  jdk8之前--2(进入sayMessage方法)   jdk8之前--5(sayMessage方法返回)
        return  s;  //jdk8之前---6  joinStr方法返回返回值
    }
}

OK,特别是使用SpringBootFlux编程时,集合流配上lambda外加函数式编程思想,好用的不得了。

猜你喜欢

转载自blog.csdn.net/cszhang570221322/article/details/84656329