在Java三目运算符语句中如何捕获异常?

3

我正在重新格式化一些遗留代码,而其中有几个变量赋值条件性地将变量分配给两个格式化函数的输出结果,使用异常捕获来实现,如下所示:

String myString;
try {
    myString= foo(x);
} catch (Exception e) {
    myString= bar(x);
}

这似乎是滥用异常处理,并且对于大量的变量赋值,存在大量重复的样板代码。不需要深入挖掘foo以识别可能会引起异常的条件,我是否可以使用三元运算符表达式来简化呢?例如:

String myString = foo(x) ? foo(x) : bar(x)

但是,如何捕获可能由foo(x)引发的异常呢?有没有一种方法可以在这一行代码中实现?或者,如果不行,有没有更好的一行代码表达方式,可以根据可能出现的异常来选择两个赋值之间的选项?我正在使用Java 8。


8
最好保持原样。三元运算符没有那个概念。此外,foo(x) ? foo(x) : bar(x) 至少多调用了一次 foo(x) - ernest_k
复杂/长的三元语句很难阅读,而且让它们变得更长或更复杂并没有真正的优势,因此我会倾向于可读性而不是紧凑性。 - JonK
我添加了一个后续问题:如果三元运算符无法实现此功能,是否有另一种类似的Java单行代码,可以根据异常条件在两个赋值之间进行选择? - workerjoe
@workerjoe 请将您的改进作为问题正文的编辑,而不是评论。 - Basil Bourque
@BasilBourque 我都做了。 - workerjoe
3个回答

4

可以如下使用延迟计算技术:

String myString = attempt(() -> foo(x), () -> bar(x));

public static <T> T attempt(Supplier<T> a, Supplier<T> b) {
    try {
        return a.get();
    } catch (Exception e) {
        return b.get();
    } 
}

这不太好,只是完整重构中的一个阶段。

针对这些结构的一种模式是进程结果消息可能会抛出 IOException 异常。

当数据是可选时,一种丑陋的模式是 NullPointerException 或类似的东西。然后,更复杂的重设计通过 Optional.ofNullable.map 到另一个 Optional 可能是可行的。

简而言之,我没有看到一种干净的方法。


1
由于 foo 显然可以抛出 Exception(而不仅仅是 RuntimeException),你应该使用 Callable 而不是 Supplier,这样更为合适。 - Slaw
@Slaw 完全正确。不幸的是,那么解决方案将不再是轻量级的。现在答案应该只处理 RuntimeException。把它变成一个答案。 - Joop Eggen
请查看以下链接以了解“Callable”和Java 8的“Supplier”之间的区别:https://softwareengineering.stackexchange.com/questions/254311/what-is-the-difference-between-callablet-and-java-8s-supplier - Joop Eggen

2
"最初的回答"已经很清晰了。但是我想补充一下你的陈述:
“这是大量重复的样板代码,需要大量的变量分配。”
如果您不想重复分配变量,可以创建一个新方法来返回String值,如下所示:
String myString = assign(x);

String assign(String x) {
    try {
        return foo(x);
    } catch (Exception e) {
        return bar(x);
    }
}

你只需要使用上述方法一次分配变量。最初的回答。

1
考虑这种情况。
String myString;
try {
    myString= foo(x);
} catch (Exception e) {
    myString= bar(x);
}

如果foo(x)由于无法处理带有UTF-16字符的字符串而抛出异常,那么我们将使用bar(x)
在三元运算符的情况下,如果你首先检查foo(x)并且它抛出错误,那么整个程序都会出错,这将导致我们在三元运算符周围放置一个try语句。
没有原始代码很难说开发人员为什么这样做,但上面是他们选择这种设计实践的情况概述。还要注意,并非所有旧代码都是不好的,在这种情况下;旧代码可以工作,易于维护,并且对于新开发人员来说易于阅读。因此,最好按照注释的方式保留它。
编辑
你说你想要一些减少样板文件的一行式代码。你可以像这样做:
void hee(String mystring) {
    try {
        myString= foo(x);
     } catch (Exception e) {
        myString= bar(x);
     }
}

将此函数放入实用程序类中,然后将myString = foo(x)更改为hee(x)即可,因为您的原始对象X不是基本java类型。 该解决方案向后兼容(由于这是旧代码,我不确定您正在使用哪个jdk),并且需要最少的说明。

我明白为什么我提出的三元运算符表达式会失败。 我真正的问题是,是否有类似的一行代码可以根据异常条件选择赋值,即回退到默认值。 - workerjoe
1
@workerjoe 上面是一个简单的解决方案,可以与您现有的遗留代码配合使用。 - washcloth
你似乎正在尝试通过将值分配给myString参数来“返回”foobar的结果。这不起作用,因为Java是按值传递的。 - Slaw
@Slaw,“在Java中,对象是按引用传递的,但在内部它是值传递。原始数据直接通过值传递。”和“在Java中,字符串是非原始数据类型,因为它总是大写写入。以大写字母开头的任何数据类型都是非原始数据类型。” - washcloth
传递的值是对象的引用。换句话说,引用被复制,但它指向同一个对象。然而,重新分配参数对调用该方法的代码没有影响。请参见 https://dev59.com/EXVD5IYBdhLWcg3wQJOT - Slaw
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接