初识Lambda表达式3----JDK提供函数式接口的引出2---java

写在前面的话

    总感觉上篇博客有些东西需要补充,于是思来想去写下了本篇博客…

1.场景引入

    场景: 假如有这样一种场景,我们的项目里有好多方法,这些方法的参数都包含一个接口,这些接口虽然其功能各不相同,但是却都有一个共同点,就是它们输入参数的个数和类型相同,返回结果的类型也相同.那具体开发中该如何去处理这种情况呢???

    解决方式1: 很容易想到的一种解决方式就是我们先去定义这样一个个的接口,再定义一个个的类去实现这些接口,然后将这些实现了指定接口的类作为参数传递给方法(多态),再去解决具体的问题.--------或者定义完接口后,不再去定义具体的类,而直接使用匿名内部类的方式,将所需要的接口参数传递给方法.这两种解决办法都可以算作比较传统的方法,而且可以做到见名之义,但是有一个比较大的缺点,就是需要写的代码太多,比较复杂. 栗子如下:

package com.nrsc.lambda.FunctionInterfaceDemo;

//两个数相加的接口
interface TwoNumberPlus {
    int plus(int x, int y);
}

//两个数相减的接口
interface TwoNumberMinus {
    int minus(int x, int y);
}

class TwoNumberCalculateClass {
    private int x;
    private int y;

    public TwoNumberCalculateClass(int x, int y) {
        this.x = x;
        this.y = y;
    }

    //两个数相加
    public int twoNumberPlus(TwoNumberPlus twoNumberPlus) {
        return twoNumberPlus.plus(this.x, this.y);
    }

    //两个数相减
    public int twoNumberMinus(TwoNumberMinus twoNumberMinus) {
        return twoNumberMinus.minus(this.x, this.y);
    }
}

public class Demo1 {
    public static void main(String[] args) {
        TwoNumberCalculateClass twoNumberCalculateClass = new TwoNumberCalculateClass(7, 8);

        //两数相加
        int res_plus = twoNumberCalculateClass.twoNumberPlus(new TwoNumberPlus() {
            @Override
            public int plus(int x, int y) {
                return x + y;
            }
        });
        System.out.println(res_plus);  //15

        //两数相减
        int res_minus = twoNumberCalculateClass.twoNumberMinus(new TwoNumberMinus() {
            @Override
            public int minus(int x, int y) {
                return x - y;
            }
        });
        System.out.println(res_minus);  //-1
    }
}

    解决方式2.1: 当然还有一个看起来比较取巧的方法,那就是我们定义一个比较通用的接口,然后使用匿名内部类的方式,去完成我们的任务.栗子如下:

package com.nrsc.lambda.FunctionInterfaceDemo.demo1;

//两个数之间进行计算的通用接口
interface TwoNumberCalculateInterface {
    int calculate(int x, int y);
}

class TwoNumberCalculateClass {
    private int x;
    private int y;

    public TwoNumberCalculateClass(int x, int y) {
        this.x = x;
        this.y = y;
    }

    //两个数进行计算
    public int twoNumberCalculate(TwoNumberCalculateInterface twoNumberCalculate) {
        return twoNumberCalculate.calculate(this.x, this.y);
    }

}

public class Demo1 {
    public static void main(String[] args) {
        TwoNumberCalculateClass twoNumberCalculateClass = new TwoNumberCalculateClass(7, 8);

        //两数相加
        int res_plus = twoNumberCalculateClass.twoNumberCalculate(new TwoNumberCalculateInterface() {
            @Override
            public int calculate(int x, int y) {
                return x + y;
            }
        });
        System.out.println(res_plus); //15

        //两数相减
        int res_minus = twoNumberCalculateClass.twoNumberCalculate(new TwoNumberCalculateInterface() {
            @Override
            public int calculate(int x, int y) {
                return x - y;
            }
        });
        System.out.println(res_minus);  //-1
    }
}

    从上面的两个栗子来看,方式2.1中的通用接口方式是可行的,但是在jdk8出来之前,应该很少有人会去这么去做,为什么呢?我想最主要的原因应该是,第二种方式其实并没有比第一中方式省下来多少行代码(主要的代码量都在方法的重写上),而且这样还会让代码做不到见名之义的效果.

比较有意思的一个地方

    JDK8出来以后,我们发现2.1中所提到的这种通用接口却直接成了JDK源码,而且还一下整出了40个(java.util.function包内的函数式接口). 我想这肯定与lambda表达式的简洁,以及它真正关心的只是输入参数和返回结果的特性相关(归纳一句就是可以使匿名内部类的方式更加简洁). 举个栗子:

package com.nrsc.lambda.FunctionInterfaceDemo;

import java.util.function.BinaryOperator;


class TwoNumberCalculateClass {
    private int x;
    private int y;

    public TwoNumberCalculateClass(int x, int y) {
        this.x = x;
        this.y = y;
    }

    //使用JDK自带的函数式接口
    public int twoNumberCalculate1(BinaryOperator<Integer> binaryOperator) {
        return binaryOperator.apply(this.x, this.y);
    }
}

public class Demo1 {
    public static void main(String[] args) {
        TwoNumberCalculateClass twoNumberCalculateClass = new TwoNumberCalculateClass(7, 8);

        /**
         * 使用JDK自带的函数式接口以及lambda表达式
         */
        int res1 = twoNumberCalculateClass.twoNumberCalculate1((x, y) -> x + y);
        System.out.println(res1);  //15

        /**
         *  当然也可以使用原来的匿名内部类的方式----使用JDK自带的函数式接口以及匿名内部类
         */
        int res2 = twoNumberCalculateClass.twoNumberCalculate1(new BinaryOperator<Integer>() {
            @Override
            public Integer apply(Integer integer, Integer integer2) {
                return integer + integer2;
            }
        });

        System.out.println(res2);


    }
}

    但是仅仅如此吗?肯定不是!!!使用JDK自带的函数式接口+lambda表达式虽然可以让匿名内部类的方式大为简化,但仍然会让人感觉代码写的不是那么见名之义, 所以 JDK提供的函数式接口的出现肯定还有其他比较重要的作用 -----比如下篇博客将会介绍到的方法引用.

    接下来将介绍一下部分JDK提供的函数式接口的简单使用方式,其实这些接口用起来都很简单,大家尝试着多写写应该就可以掌握,我做的几个小栗子代码如下:

package com.nrsc.lambda.FunctionInterfaceDemo;

import java.text.DecimalFormat;
import java.util.function.*;

/**
 * 部分JDK提供的函数式接口使用样例
 */
public class Demo2 {
    public static void main(String[] args) {

        //断言函数接口--- 接受一个参数,返回一个布尔类型的结果
        Predicate<Integer> fun1 = i -> i > 5;
        System.out.println(fun1.test(4));

        //JDK还提供了一些带类型的函数式接口,用这些接口我们就不必再指定泛型了,如下:
        IntPredicate fun11 = i -> i==10;
        System.out.println(fun11.test(10));

        //消费者----接受一个输入参数并且无返回结果
        Consumer fun2 = s -> System.out.println(s + " world");
        fun2.accept("hello");

        //提供者---无需输入参数, 为我们提供或返回一个参数
        Supplier<String> fun3 = () -> "hi , beijing";
        System.out.println(fun3.get());

        //Function<T,R>---输入参数类型为T,返回类型为R的函数
        Function<Integer, String> fun4 = i -> new DecimalFormat("#,###").format(i);

        //一元函数-----接受一个参数为类型T,返回值类型也为T。
        UnaryOperator<String> fun5 = s -> s.replace(",", "||");
        System.out.println(fun5.apply("嘿嘿,哈哈"));

        //BiFunction<T ,U ,R> 2个输入的函数-----输入类型为T和U,返回类型为R的函数
        BiFunction<Integer, String, Boolean> fun6 = (i, s) -> (i + s).equals("111 hello world");
        System.out.println(fun6.apply(111, " hello world"));

        //BinaryOperator<T> 二元函数----需要输入两个参数,参数类型都为T,返回类型也为T的函数
        BinaryOperator<Integer> fun7 = (s, t) -> s * t;
        System.out.println(fun7.apply(7, 8));
    }
}

猜你喜欢

转载自blog.csdn.net/nrsc272420199/article/details/84674824