可调用<t>替换,可以传递参数

时间:2017-09-26 07:52:07

标签: java

我有很多代码,每个函数都以相同的方式开始和结束。所以我开始使用Callable使其更清晰。但我想要做的是以某种方式获得每个函数(foo / doo / roo)的“检查”对象,但调用方法不允许发送参数。有更好的方法吗?

public void foo(String something, Boolean flag, Object obj) {
    callSafe(something, flag, () => /*some code capturing obj*/);
}

public void doo(String something, Boolean flag) {
    callSafe(something, flag, () => /*different code using check*/);
}

public void roo(String something, Boolean flag, Integer id) {
    callSafe(something, flag, () => /*some code using check*/);
}

private void callSafe(string something, Boolean flag, Callable<T> c) {
    try {
        Object check = someFunction(flag, something);
        if (check.IsTrue()) {
            c.call(); 
            //c.call(check); //What I want to do.
        }
    } catch(Exception e) {
        // handle exception
    }
}

我想我可以只运行“someFunction”两次(一次在可调用函数中,一次在实际函数中),但函数很慢,我不想这样做。

编辑:通过添加界面并使用@Eran建议的方法修复它。界面:

@FunctionalInterface
public interface CheckedFunction<T, R> {
    R apply(T t) throws Exception;
}

我不确定这是不是很好的做法。有什么想法吗?

3 个答案:

答案 0 :(得分:1)

我不确定Callable是否适用于首位,因为call方法会返回一个您忽略的值。

您可以使用Consumer<SomeClass>,其accept(SomeClass t)方法。

private void callSafe(String something, Boolean flag, Consumer<SomeClass> c) {
    try {
        SomeClass check = someFunction(flag, something);
        if (check.IsTrue()) {
            c.accept (check);
        }
    } catch(Exception e) {
        // handle exception
    }
}

public void roo(String something, Boolean flag, Integer id) {
    callSafe(something, flag, (SomeClass check) -> /*some code using check*/);
}

如果确实需要返回值,可以使用Function<T, R>,其R apply(T t)方法:

private void callSafe(String something, Boolean flag, Function<SomeClass,ReturnClass> f) {
    try {
        SomeClass check = someFunction(flag, something);
        if (check.IsTrue()) {
            f.apply (check);
        }
    } catch(Exception e) {
        // handle exception
    }
}

public void roo(String something, Boolean flag, Integer id) {
    callSafe(something, flag, (SomeClass check) -> /*some code using check which return an instance of ReturnClass*/);
}

答案 1 :(得分:0)

是的,还有更好的方法。

您应该研究面向方面的编程。如果您正在使用Spring,那么将Spring的运行时代理集成到您的任务中应该相当轻松。

您将需要创建包含函数的方面,创建注释以标记函数(必须是使用组件接口的公共方法的Spring组件),配置方面。

有关详细信息,请参阅https://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html

这似乎是Spring运行时方面的一个简单的示例驱动介绍:http://www.byteslounge.com/tutorials/spring-aop-example

答案 2 :(得分:0)

从表面上看,你需要Consumer<CheckResult>

 Consumer<CheckResult> c = result -> doSomethingWith(result);

但是,您需要使用已检查的异常会妨碍这一点 - Consumer.accept()无法抛出已检查的Exception

您可以编写自己的ThrowingCheckResultConsumer界面:

@FunctionalInterface
public interface ThrowingCheckResultConsumer {
     void accept(CheckResult obj) throws MyException;
}

......或更一般地说:

@FunctionalInterface
public interface ThrowingConsumer<T,E extends Exception> {
     void accept(T obj) throws E;
}

@FunctionalInterface注释告诉Java lambda可以用作此接口的实现。

现在你可以实现一个:

    ThrowingCheckResultConsumer c = cr -> doSomethingWith(cr);
    c.accept("");

或者在你的情况下:

callSafe(something, flag, cr -> doSomethingWith(cr));

...和

private void callSafe(String something, Boolean flag, ThrowingCheckResultConsumer consumer) {
    try {
        SomeClass check = someFunction(flag, something);
        if (check.IsTrue()) {
            consumer.accept(check);
        }
    } catch(MyException e) {
        // handle exception
    }
}

在你的问题中,你抓住了Exception。我使用过MyException,因为广泛捕捉Exception通常被认为是糟糕的风格。只捕获RuntimeException和已调用的异常,您正在调用的代码声明。

但是,如果必须,可以在此代码中将MyException替换为Exception

有些库提供Checked*功能接口。 Vavr就是一个。 Vavr CheckedConsumer.accept()抛出Throwable

尝试提出一个不会抛出已检查异常的消费者可能会更容易。如果您控制了例外情况,请考虑延长RuntimeException。或者在消费者中捕获它们并将其重新包裹在RuntimeException