当前位置: 首页 > 工具软件 > Vavr > 使用案例 >

Vavr 使用教程 函数式工具库

单修德
2023-12-01

一、依赖

        <dependency>
            <groupId>io.vavr</groupId>
            <artifactId>vavr</artifactId>
        </dependency>

二、使用示例

package com.cagmss.function;

import com.cagmss.common_core.utils.number.NumberUtils;
import io.vavr.Function1;
import io.vavr.Function2;
import io.vavr.Function3;
import io.vavr.Tuple2;
import io.vavr.control.Option;
import io.vavr.control.Try;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Objects;

@Slf4j
public class FunctionDemo {
    public static void main(String[] args) {


        // Integer orNull = Option.of(0)
        //         .map(o -> 1 / o)
        //         .transform(op->op.get());
        // System.out.println(orNull);


        // String s = Try.of(() -> 1 / 0)
        //         .recover(Exception.class, (e) -> null)
        //         .filter(Objects::nonNull)
        //         .map(o -> o.toString())
        //         .get();
        //
        // System.out.println(s);

        tryTest();
    }

    private static void tryTest() {
        // onFailure 当 元素为空 或 发送异常时 执行消费 (onFailure实际类似于peek 瞧一下异常)
        // onSuccess 有元素 并且无异常时执行
        Try<Integer> onFailure = Try.of(() -> 1 / 1)
                // .filter(i -> i > 10)
                .onFailure((e) -> log.error("失败{}", e.getMessage()))
                .onFailure(NullPointerException.class, (ne) -> System.out.println(ne.getMessage())) // 消费指定异常
                .onSuccess(o -> log.info("成功{}", o));

        // 关闭流
        Try<FileReader> readers = Try.of(() -> new FileReader(""));
        readers.mapTry(BufferedReader::new)
                .andThenTry((name) -> {
                    int i = 1 / 0;
                    while (true) {
                        String line = name.readLine();
                        if (Objects.isNull(line)) {
                            break;
                        }
                        System.out.println(line);
                    }
                }).onFailure(e -> log.error(e.getMessage()))
                .andFinally(() -> readers.andThenTry(InputStreamReader::close));

        // withResources 接收一个AutoCloseable 实现类,of的前一个阶段就会关闭,因此下面的用法是错误的,暂时不知道能干什么用
        // 如果想操作io 可以像上面的示例写法
        // Try.withResources(() -> new BufferedReader(new FileReader("")))
        //         .of(BufferedReader::readLine)
        //         .get();


        // failed 获取异常对象,如果未出现异常,则get时会抛出new NoSuchElementException("Success.failed()"))
        Try<Throwable> failed = Try.of(() -> 1 / 0)
                .peek(i -> log.info(String.valueOf(i)))
                .failed();

        // getCause 获取异常 无异常时抛出 throw new UnsupportedOperationException("getCause on Success");
        Throwable cause = Try.of(() -> 1 / 0)
                .getCause();

        // andFinally 无论是否发生异常 都会执行
        Try<Integer> andFinally = Try.of(() -> 1 / 1)
                .peek(i -> log.info(String.valueOf(i)))
                .andFinally(() -> log.info("最终执行"))
                .andFinallyTry(() -> log.info("执行"));

        // andThenTry、andThen,流程中对数据的一次消费,无异常 且 未被过滤 时执行
        Try<Integer> integers = Try.of(() -> 1 / 1)
                .filter(i -> i > 10)
                .peek(i -> log.info(String.valueOf(i)))
                .andThenTry((i) -> log.info("andThenTry {}", i))
                .andThenTry((i) -> log.info("andThenTry {}", i));

        // filter 过滤元素 元素非空时执行
        Try<Integer> integerTry = Try.of(() -> 1 / 1)
                // .filter(i -> i > 10)  // 过滤失败 get() 抛出默认异常 new NoSuchElementException("Predicate does not hold for " + get())
                .filter(i -> false, (o) -> new RuntimeException("过滤失败,创建异常")) // 断言为false  抛出指定异常 可接受断言参数
                // .filter(i -> i > 10, () -> new RuntimeException("i小于10异常")) // 断言为false  抛出指定异常
                .peek(i -> log.info("过滤结果为true")) // 过滤为false 则不执行
                .onFailure((e) -> log.error("filter失败{}", e.getMessage())) // 过滤失败执行 消息:Predicate does not hold for 1
                .onSuccess(o -> log.info("filter成功{}", o));

        // 元素映射,无异常 且 元素非空时执行
        Try<Integer> integers1 = Try.of(() -> 1 / 1)
                // .filter(i->i>10)
                .map(i -> i + 1)
                .mapTry(i -> i * 10)
                .onFailure((e) -> log.error("map失败{}", e.getMessage()))
                .onSuccess(o -> log.info("map成功{}", o));

        // fold 折叠, 异常或无值左边,无异常有值右边
        Integer fold = Try.of(() -> 1 / 1)
                .fold(e -> 10, i -> 10);


        // recover 捕获某些异常,然后替换原有值
        Integer integers2 = Try.of(() -> 1 / 0)
                .peek(NumberUtils::throwInvalidDouble)
                // .filter(o -> o > 10)
                .recover(IOException.class, e -> {
                    log.warn("IOException:" + e.getMessage());
                    return 1;
                })
                .recover(ArithmeticException.class, e -> {
                    log.warn("ArithmeticException:" + e.getMessage());
                    return 1;
                })
                .onFailure(e -> log.error(e.getMessage()))
                .getOrElseThrow(e -> new RuntimeException(e));

        // recoverWith 与 recover类似,返回一个新的Try实例

        Try<Integer> integers3 = Try.of(() -> 1 / 0)
                .recoverWith(Exception.class, e -> Try.of(() -> 0));

        // Try类型嵌套扁平化
        Try<Integer> integers4 = Try.of(() -> Try.of(() -> 0))
                .flatMap(t -> t);

        System.out.println(integers4.get());
    }

    private static void function() {
        Function2<Integer, Integer, Integer> f21 = (a, b) -> a - b;
        Function2<Integer, Integer, Integer> f22 = (a, b) -> a * b;

        // fr(f22(a,b))  将结果传递给下一个函数,函数只能是一元的,因为返回值只有一个
        Function2<Integer, Integer, Integer> then = f21.andThen((r) -> r + 10);

        // 将参数包装为tuple
        Function1<Tuple2<Integer, Integer>, Integer> tupled = f21.tupled();

         科里化 f(a,b,c) => f(a) f(b) f(c)
        // 将第一个参数值固定,返回一个降级后的参数
        Function1<Integer, Integer> apply1 = f21.curried().apply(1);
        // 继续科里化后如果无参了,则将结果返回
        Integer apply = apply1.curried().apply(1);
        System.out.println("科里化 " + apply);

        // 函数参数逆转
        Function2<Integer, Integer, Integer> reversed = f21.reversed();
        // 部分应用,将参数值固定,返回一个降参的函数,和科里化有些类似,
        Function1<Integer, Integer> apply2 = reversed.apply(1);
        Integer apply3 = apply2.apply(2);
        System.out.println("逆转,部分应用 " + apply3);
        // 区别在于科里化将多参函数转换为1个参数的函数
        Function3<Integer, Integer, Integer, Integer> f3 = (a, b, c) -> a + b + c;
        Function1<Integer, Function1<Integer, Integer>> apply5 = f3.curried().apply(1);
        Integer res = apply5.apply(4).apply(3);
        System.out.println("3参科里化 " + res);
        // 部分应用
        Function1<Integer, Integer> apply6 = f3.apply(1, 2);
        Integer apply7 = apply6.apply(1);
        System.out.println("3参部分应用" + apply7);


        // 返回当前函数的参数个数
        int arity = f21.arity();
        System.out.println("函数参数数量 " + arity);

         记忆,参数相同的情况下,反复执行函数 只计算一次,
        // 原理:将函数参数封装元组作为 map的key
        Function2<Integer, Integer, Integer> memoized = f21.memoized();
        Integer apply4 = memoized.apply(1, 2);
        System.out.println(apply4);
        apply4 = memoized.apply(2, 1);
        System.out.println(apply4);


         函数静态方法部分:

        // 给函数一个常量值,无论传什么参数,结果依然为常量值
        Function2<Object, Object, Integer> constant = Function2.constant(2);
        System.out.println("函数常量 " + constant.apply(1, 1));
        Function1<Object, Integer> apply8 = constant.apply(1);
        System.out.println(apply8.apply(2));

        // 接收一个 非检查异常 的函数体,将返回值封装为option
        // 非get方法会隐藏异常
        // get方法会将真实异常隐藏,但会报没有结果异常
        Function2<Integer, Integer, Option<Integer>> lift = Function2.lift((a, b) -> a / b);
        Option<Integer> option = lift.apply(1, 0);
        Integer orNull = option.getOrNull();
        System.out.println("getOrNull" + orNull); // null
        // System.out.println("option.get() = " + option.get()); // java.util.NoSuchElementException: No value present
        // 接收一个 非检查异常 的函数体,将结果封装为try
        Function2<Integer, Integer, Try<Integer>> lift2 = Function2.liftTry((a, b) -> a / b);
        Try<Integer> apply9 = lift2.apply(1, 0);
        // System.out.println("apply9.get() = " + apply9.get()); // java.lang.ArithmeticException: / by zero

        Function2<Integer, Integer, Integer> narrow = Function2.narrow((a, b) -> a + b);
        Integer apply10 = narrow.apply(1, 2);
        System.out.println(apply10);
    }
}

 类似资料: