我有很多代码,每个函数都以相同的方式开始和结束。所以我开始使用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;
}
我不确定这是不是很好的做法。有什么想法吗?
答案 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
。