java8 笔记 - Function(二)

本文通过四则运算的实例介绍了Java中传统方法与Lambda表达式的使用区别,展示了如何利用Lambda表达式灵活地实现不同运算需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

四则运算

先来看一个计算两个整数四则运算的例子,我会这样写:

public class LambdaTest {

    public static void main(String[] args) {

        Integer num1 = 16, num2 = 2;

        System.out.println(Calculator.add(num1, num2));

        System.out.println(Calculator.minus(num1, num2));

        System.out.println(Calculator.multiply(num1, num2));

        System.out.println(Calculator.divide(num1, num2));
    }
}

class Calculator {

    public static Integer add(Integer num1, Integer num2) {
        return num1 + num2;
    }

    public static Integer minus(Integer num1, Integer num2) {
        return num1 - num2;
    }

    public static Integer multiply(Integer num1, Integer num2) {
        return num1 * num2;
    }

    public static Integer divide(Integer num1, Integer num2) {
        return num1 / num2;
    }
}
输出:
18
14
32
8

但是如果需要计算平方,那么上面的方式就需要修改 Calculator,添加一个平方的方法,不符合开闭原则(对修改关闭,对扩展开放),那么我会像下面这样写。

public class LambdaTest {

    public static void main(String[] args) {

        Integer num1 = 16, num2 = 2;

        System.out.println(new AddCalculator().compute(num1, num2));

        System.out.println(new MinusCalculator().compute(num1, num2));

        System.out.println(new MultiplyCalculator().compute(num1, num2));

        System.out.println(new DivideCalculator().compute(num1, num2));
    }


}

interface Calculator {
    Integer compute(Integer num1, Integer num2);
}

class AddCalculator implements Calculator {
    @Override
    public Integer compute(Integer num1, Integer num2) {
        return num1 + num2;
    }
}

class MinusCalculator implements Calculator {
    @Override
    public Integer compute(Integer num1, Integer num2) {
        return num1 - num2;
    }
}

class MultiplyCalculator implements Calculator {
    @Override
    public Integer compute(Integer num1, Integer num2) {
        return num1 * num2;
    }
}

class DivideCalculator implements Calculator {
    @Override
    public Integer compute(Integer num1, Integer num2) {
        return num1 / num2;
    }
}
输出:
18
14
32
8

这里简单使用了策略模式,添加平方函数,只要新增加个类实现Calculator并计算平方就好了,对已有的代码没有修改。但是这还是有一个问题,我必须事先知道有哪些函数,我才能够用,这也是策略模式的缺点:

  • 客户端必须知道所有的策略类,并自行决定使用哪一个策略类
  • 客户端必须理解这些算法的区别,以便适时选择恰当的算法类

那么我们看看用java8的方式是如何解决的:

public class LambdaTest {

    public static void main(String[] args) {

        Integer num1 = 16, num2 = 2;

        MyCalculator<Integer> calculator = new MyCalculator<>();


        System.out.println(calculator.comput(num1, num2, (n1,n2)-> n1 + n2));

        System.out.println(calculator.comput(num1, num2, (n1,n2)-> n1 - n2));

        System.out.println(calculator.comput(num1, num2, (n1,n2)-> n1 * n2));

        System.out.println(calculator.comput(num1, num2, (n1,n2)-> n1 / n2));

    }
}

class MyCalculator<T> {

    public T comput(T t1, T t2, BiFunction<T, T, T> function) {
        return function.apply(t1, t2);
    }
}
输出:
18
14
32
8

传递行为

使用java8的例子,我们可以看到,根据MyCalculator的compute方法,我们根本不知道它具体的运算规则是什么,是加法、减法还是平方等等,而这种运算行为是通过调用者传递进来的,也就是说Lambda表达式传递的是一种行为。

BiFunction

BiFunction是java8提供的一个函数式接口,它代表了一个函数,表示接收两个参数返回一个值。这与数学上的四则函数式是类似的。

@FunctionalInterface
public interface BiFunction<T, U, R> {

    R apply(T t, U u);

    default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t, U u) -> after.apply(apply(t, u));
    }
}
BiFunction :apply

方法接收两个参数,分别是 T,U 类型;返回一个值,返回值类型是 R;刚才我们的四则运算的例子这三个参数类型都是一样的。我们再聚一个例子:

这个例子的功能是将数字和字符串进行拼接,返回一个字符串。

public class LambdaTest {

    public static void main(String[] args) {

        BiFunction<Integer, String, String> biFunction = (num, str) -> num + ":" + str;

        System.out.println(biFunction.apply(888, "world"));

    }
}
输出:
888:world

BiFunction还有一个默认方法andThen,在看andThen方法之前我们先看一下andThen方法的参数Function

Function

Function 同样也是一个函数式接口,它的抽象方法apply,接收一个参数,返回一个值。

@FunctionalInterface
public interface Function<T, R> {

    R apply(T t);

    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    static <T> Function<T, T> identity() {
        return t -> t;
    }
}
Function:apply:

这个例子是字符串转换操作,将其转换成大写、小写:

str -> str.toUpperCase(): 表示输入一个参数,返回一个值,与Function的apply一致。

public class LambdaTest {

    public static void main(String[] args) {

        System.out.println(convert("Hello World", str -> str.toUpperCase()));

        System.out.println(convert("Hello NodeJs", str -> str.toLowerCase()));

    }

    public static String convert(String str, Function<String,String> function){
       return function.apply(str);
    }

}
输出:
HELLO WORLD
hello nodejs

apply 的输入参数 T 和返回参数 R 也可以是不同的:

str -> Integer.parseInt(str):表示一个输入参数(String),一个返回值(Integer)符合

public class LambdaTest {

    public static void main(String[] args) {

        System.out.println(convert("12", str -> Integer.parseInt(str)));
    }

    public static Integer convert(String str, Function<String,Integer> function){
       return function.apply(str);
    }

}
输出:
12
Function : compose and andThen

表示function的者,优先调用参数before的apply方法,然后将before的返回值作为当前function的apply的输入参数;而andThen与之相反,优先调用当前function的apply,然后将返回值作为after的输入参数。

public class LambdaTest {

    public static void main(String[] args) {

        Function<Integer,Integer> function = value -> value + 3;

        Function<Integer,Integer> function2 = value -> value * 2;

        //优先算funtion2,所以为 1 * 2 + 3 = 5
        System.out.println(function.compose(function2).apply(1));

        //优先算function,所以为 (1 + 3)* 2 = 8
        System.out.println(function.andThen(function2).apply(1));

    }
}
输出:
5
8
BiFunction : andThen

现在我们回头看一下BiFunction的andThen方法,它接收一个Function类型的参数,先调用BiFunction的apply,然后BiFunction的返回值作为Function的输入。 那为什么BiFunction没有compose方法呢?
假如BiFunction有compose方法,那么优先调用参数before,然后返回值作为BiFunction的输入,但是BiFunction需要两个输入,方法的返回值只有一个,所以BiFunction没有compose方法。

例子:优先调用BiFunction,将两个字符串进行拼接,然后调用Function,输入一个字符串,输出一个double。

public class LambdaTest {

    public static void main(String[] args) {

        Function<String,Double> function = str -> Double.parseDouble(str);

        BiFunction<String,String,String> biFunction = (integer, decimal) -> integer + "." + decimal;

        System.out.println(biFunction.andThen(function).apply("3", "1415926"));

    }
}
输出:
3.1415926

DoubleToIntFunction

Function的输入参数和输出参数是任意的,DoubleToIntFunction属于一个具体的Function,输入参数必须是double,而输出参数必须是int

@FunctionalInterface
public interface DoubleToIntFunction {

    int applyAsInt(double value);
}

例子:

value -> new Double(value).intValue(): 可以表示输入一个double参数,返回一个int值

public class LambdaTest {

    public static void main(String[] args) {

        DoubleToIntFunction function = value -> new Double(value).intValue();

        System.out.println(function.applyAsInt(3.1415926));
    }
}

java.util.function 包还提供了很多Function,IntFunction、LongFunction等等,都大同小异

java.util.function

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值