Java:没有返回值的三元运算符(用于方法调用)

58

我在想是否有可能进行三元操作,但不返回任何内容。

如果Java中不可能,那么其他语言是否可以实现,哪些语言适用?

name.isChecked() ? name.setChecked(true):name.setChecked(false);

1
在JavaScript中是可能的,例如在这里:https://dev59.com/Km025IYBdhLWcg3wAxJ9#6260001 - blong
7个回答

65

不,你不能这样做。但是相较于使用 if-else 语句,这种做法有什么意义呢?你真的为了节省7个字符而这样做吗?

if (name.isChecked()) {
    name.setChecked(true);
} else {
    name.setChecked(false);
}

或者如果你喜欢不好的风格:

if (name.isChecked()) name.setChecked(true); else name.setChecked(false);

不要在意你可以仅仅使用以下方式(在这种情况下):

name.setChecked(name.isChecked());

三元运算符或“条件”运算符的用途是将条件引入一个表达式中。换句话说,这样写:

int max = a > b ? a : b;

这是缩写,意思等同于:

int max;
if ( a > b ) {
    max = a;
} else {
    max = b;
}

如果没有产生值,条件运算符就不是一种捷径。


4
使用Stream.forEach lambda表达式时,有些情况下我认为编写(item -> item.isA() ? doA() : doB())比使用大括号和if / else语句更加优雅。 - Jamby
2
不能这样做的论据是什么?在某些情况下,这只是为了使代码更清晰合理。 - html_programmer
@html_programmer:当然,还可以提出其他论点,但我个人认为,使用带有副作用和条件表达式的控制结构会导致更清晰的代码。在我的看法中,将副作用埋藏在表达式中会隐藏代码的最重要部分,无论是在这里还是在相关的 someConditionTrue && doSideEffect() 中,有时你会看到这种情况。但是,像许多代码风格一样,这是高度主观的。 - Mark Peters

17
我想知道是否可能进行三元操作,但不返回任何内容。
不可能:
1. 第二个和第三个操作数需要是非void表达式;即它们必须产生一些实际值。 "如果第二个或第三个操作数表达式是void方法的调用,则会在编译时出现错误。" - JLS 15.25
2. 三元表达式是一个表达式,不能用作语句。 "某些类型的表达式可以通过在分号后跟它们来用作语句。" ... 三元表达式不是其中的一种 - JLS 14.8
如果你真的非常想使用三元表达式但不使用表达式的值,那么最简单的方法是将该值赋给一个虚拟变量,并添加注释以抑制有关未使用变量的警告。
但更好的主意是使用普通的if语句。
“如果在Java中不可能,那么在其他语言中是否可能?如果可能,哪些语言适用?”
我有点生疏,但我相信C、C++和Perl都允许在其值未被使用的地方使用任意表达式。

9
有时候,您可以在方法参数上使用三元运算符来解决您的请求。
name.setChecked(name.isChecked() ? true : false);

顺便提一下,您问题的最佳解决方案是:
name.setChecked(name.isChecked());

1

我认为问题中的用例只是一个糟糕的例子,因为它等同于以下语句:

name.setChecked(name.isChecked());

这句话本身也没有意义。但意图是明确的,确实有许多相关的用例。

唯一可行且通用的解决方案是添加一个像这样的帮助方法:

static void ternaryVoid(boolean condition, Runnable ifTrue, Runnable ifFalse) {
    (condition ? ifTrue : ifFalse).run();
}

并像这样使用它:
ternaryVoid(name.isChecked(), () -> name.setChecked(true), () -> name.setChecked(false));

但这失去了三元运算符的优雅,只有在代码的多个部分中使用且毫秒不重要时才值得“努力”。

但是与if-else语句相比,这有什么意义呢?你真的想节省7个字符吗?

我很惊讶这样的陈述以反问的形式出现。是的,在函数式编程的背景下,节省4行并使代码更加优雅非常重要。

此外,是否 void 方法返回完整的 Void 是至少可以争论的。从逻辑上讲,它们返回已完成任务的通知。这就是为什么在逻辑上,无论是否返回任何内容,三元表达式都同样有意义:

condition ? doThis() : doThat();

这是一个现实世界中的示例,展示了一个类可以每秒处理数百万个增量更新:

public class DataHandler {

    private final TreeMap<Integer, Long> tree = new TreeMap<>();

    public void onUpdate(int price, long amount) {
        if (amount == 0) {
            tree.remove(price);
        } else {
            tree.put(price, amount);
        }
    }
}

如果被允许,onUpdate() 方法可以像这样使用简洁的三元表达式:
public void onUpdate(int price, long amount) {
    (amount == 0) ? tree.remove(price) : tree.put(price, amount); // compilation error
}

幸运的是,在这种情况下,两种目标方法都返回值,并且这些值是相同类型的,在本例中为Long。这使得可以使onUpdate方法返回之前的amountprice时的值(这甚至是有用的)。
public Long onUpdate(int price, long amount) {
    return (amount == 0) ? tree.remove(price) : tree.put(price, amount);
}

...或者,作为替代方法(例如,在方法由接口确定的情况下),使用一个虚拟变量并抑制其无用警告:

public void onUpdate(int price, long amount) {
    @SuppressWarnings("unused")
    Long dummy = (amount == 0) ? tree.remove(price) : tree.put(price, amount);
}

否则,这些解决方案并不适用,正如其他人回答的那样,并不存在。例如,可以尝试以下方法:
Consumer<Void> dummy = (x) -> {};
dummy.accept(/*...*/);

但有趣的是,第二行编译时既不需要任何参数也不需要无效参数。似乎最好的通用解决方案是上述辅助方法ternaryVoid()

0
在Java中,以下代码是不可能的:
(your-condition) ? (true-statements) : (false-statements)

例如,您无法编译以下代码片段:

(1==1) ? System.out.println("") : System.out.println("");

你遇到了以下编译错误:

The left-hand side of an assignment must be a variable

(你的条件) ? (真语句) : (假语句) 在Java中是可行的,但它必须返回一个值(不能是void),并且你必须将其赋值给一个变量。 - jalv1039

0

你必须返回一些值,如果你希望它像一个没有返回值但执行某些操作的void方法那样工作,它将无法正常工作。

希望这可以帮到你...


1
这个问题已经有答案了。请阅读常见问题解答以了解如何正确提问 - zuazo

0

不过在C++中,你可以编写一个返回void()的三元运算符,它在空的if语句中比else更有用。当将条件倒置变为单行if时,如果太长(在表达式中,而不是lambda函数),则可以使用它。

然而,它们有一些限制,我不建议在单行语句中嵌套它们(尤其是非三元语句中的主体),除非像else if这样的清晰的技巧。

关于你的示例,当直接返回条件时,三元运算符并不实用,即使条件相反,也可以在条件之前加上!而不使用三元运算符。


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