9

我有两个集合,并且根据是否满足某些条件将项目添加到这些集合中的一个或另一个。

不知不觉中,我偶然发现了写作是合法的事实

(test(foo) ? cOne : cTheOther).add(foo);

代替

if (test(foo)) {
 cOne.add(foo);
} else {
 cTheOther.add(foo);
}

虽然第一个让我觉得自己很聪明(总是加分),但我不确定长期的可读性、可维护性等。我看到的基本优势是,如果我知道我总是会做同样的事情,它成为更改方法的一个位置(而不是两个,或者如果我通过条件运算符实现 switch 语句,则可能是多个)。当情况并非如此时,就会出现主要的缺点(即,我需要为某些情况而不是其他情况添加方法调用)。

您认为这两种方法(或其他解决方案)的优缺点是什么?

如果您不认为使用条件运算符来设置调用方法的对象的这个特定实例是正确的选择,那么在某些情况下它是合理的吗?

4

9 回答 9

29

一个更简单的代码片段是

SomeClass component = test(foo) ? cOne : cTheOther;
component.add(foo);

换句话说,将分配与使用分开。

于 2010-01-25T15:27:17.170 回答
5

尽管示例很聪明,但可读性和可维护性始终是最聪明的想法。

关于条件运算符,您最多只能有两个值,如果您的条件超出该最大值,它可能会变得不可读。条件运算符不是处理不同值的标准方法。

于 2010-01-25T15:25:51.893 回答
1

我反对在 if 语句的每个分支中长期调用函数,因为并不总是很清楚要调用的函数是否相同,如果您需要更改被调用的函数,则需要更改两个地方函数(好吧,'add' 是一个简单的例子)。出于这个原因,我通常会将正确的对象分配给一个变量(通常在 if 语句中,因为通常还有一些其他的事情也在发生)但将所有常见代码拉到条件之外。

于 2010-01-25T16:02:54.590 回答
1

用于此目的的条件运算符相当罕见,因此眼睛并不是真的在寻找它。

我喜欢我的 Java 代码看起来一致,这样我和未来的维护者就可以轻松地发现分支、过于复杂等问题。由于我在其他地方使用 if,我通常可以承担使用条件而不是执行它的成本。

如果我使用的语言是通过表达式做很多“技巧”的,比如 Python,那就是另一回事了。

于 2010-01-25T16:20:33.890 回答
1

我的首选方式是:

final boolean    result;
final Collection c;

result = test(foo);

if(result)
{
    c = cOne;;
} 
else 
{
    c = cOther;;
}

c.add(foo);

首先,我不喜欢拨打电话并且不将值分配给 temp 变量(test(foo) 调用),原因有两个:

  1. 它更容易调试(System.out.println,甚至调试器 - 如果该方法有副作用,那么只需在调试器中查看它就会再次调用它 - 从而导致副作用)。
  2. 即使没有副作用,它也会阻止您多次调用它,从而使代码更有效率。编译器/热点应该处理不需要的临时变量的删除。

其次,我不喜欢有代码,如果你模糊你的眼睛,它看起来是一样的。如果你“模糊”你的眼睛,让 cOne.add(foo) 和 cOther.add(foo) “看起来”一样。例如,如果您将其更改为 List 并使用 add(int, E) 而不是 add(E) 那么您只有一个地方可以更改代码,这意味着犯错误的更改更少(例如 cOne.add (1, foo) 和 cOther.add(2, foo) 当它们都应该是 add(1, foo))。

编辑(基于评论)

有几种选择,这取决于您如何布置代码。我可能会选择类似的东西:

private Collection<Whatever> chooseCollection(final Whatever             foo,
                                              final Collection<Whatever> a,
                                              final Collection<Whatever> b)
{
    final boolean              result;
    final Collection<Whatever> c;

    result = test(foo);

    // could use a conditional - I just hate using them
    if(result)
    {
        c = a;
    }
    else
    {
        c = b;
    }

    return (c);
}

然后有类似的东西:

for(......)
{
    final Collection<Whatever> c;
    final Whatever             foo;

    foo = ...;
    c = chooseCollection(foo, cOne, cOther);
    c.add(foo;
}

本质上,如果有意义(通常确实如此),我会为 { } 块内的任何内容创建一个方法。我喜欢有很多小方法。

于 2010-01-25T17:17:54.747 回答
1

使用条件运算符的一个潜在问题是当参数开始变得更加复杂时。例如,如果以下行引发 NullPointerException:

String aString = obj1.getValue() == null ? obj2.getString() : obj1.getValue().getString();

这三个取消引用中的哪一个导致了 NPE?obj1obj2或者obj1.getValue()有时可以通过前面代码中的推断来解决它,但并非总是如此……</p>

也就是说,比较以下两段代码:

final String aString = obj1 == null ? "default" : obj1.getString();

对比

final String aString;
if (obj1 == null) {
  aString = "default";
} else {
  aString = obj1.getString();
}

大多数人会争辩说,条件式更容易阅读,当然也更简洁。

现在,有了这个,我会使用条件来调用方法吗?不,它增加了很多视觉复杂性,而且必须记住,调试比编写代码难两倍。这意味着代码越简单,您或其他人就越容易在六个月内理解它。我很乐意在接受的答案中使用两行版本。

于 2010-01-25T21:17:52.623 回答
0

恕我直言,“完整”的长版本更具可读性,从长远来看绝对更适合维护。

于 2010-01-25T15:25:56.013 回答
0

我更喜欢第一个(或马特的中间解决方案)。它只是更短。如果在您的项目中经常使用条件运算符,人们就会习惯它并且“可读性”会增加。

或者换句话说:如果你习惯了 Perl,你可以很容易地阅读它。

于 2010-01-25T15:35:41.160 回答
0

除了 matt b 所说的,当您决定使用条件运算符时,您可以更进一步并使用这种格式:

SomeClass component = test(foo) 
   ? cOne 
   : cTheOther;
component.add(foo);

它使代码更具 if-else 的感觉,并使其更易于阅读。

于 2010-01-25T18:40:12.823 回答