代码之家  ›  专栏  ›  技术社区  ›  Carl

使用条件运算符选择调用特定方法的对象?

  •  9
  • Carl  · 技术社区  · 15 年前

    我有两个集合,以及根据是否满足某些条件添加到其中一个集合或其他集合的项。

    有点不小心,我偶然发现写是合法的

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

    而不是

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

    虽然第一个让我觉得自己很聪明(总是一个优点),但我不确定长期的可读性、可维护性等。我看到的基本优势是,如果我知道我总是要做同样的事情,它就变成了一个改变方法的位置(而不是两个,或者如果我正在实现的话,可能是很多个)。 a switch statement via conditional operators )。主要的缺点是当情况变为非情况时(即,我需要向某些情况而不是其他情况添加方法调用)。

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

    如果您不认为使用条件运算符设置调用方法的对象是正确的选择,那么是否存在合理的情况?

    9 回复  |  直到 15 年前
        1
  •  29
  •   matt b    15 年前

    一个更简单的代码片段是

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

    换言之,把任务和使用它分开。

        2
  •  5
  •   Ether    15 年前

    与示例一样聪明,可读性和可维护性始终是最聪明的想法。

    对于条件运算符,最多只能有两个值,如果条件超过了最大值,则可能无法读取。条件运算符不是处理不同值的标准方法。

        3
  •  1
  •   Andrew Aylett    15 年前

    我反对在if语句的每个分支中对函数进行长时间的手工调用,因为不总是很清楚要调用的函数是否相同,如果需要更改被调用的函数,那么有两个地方需要更改(好吧,“添加”是一个简单的例子)。出于这个原因,我通常会将正确的对象赋给一个变量(通常是在if语句中,因为通常也会有一些其他的事情发生),但是将所有公共代码从条件中拉出来。

        4
  •  1
  •   Ether    15 年前

    我的首选方法是:

    final boolean    result;
    final Collection c;
    
    result = test(foo);
    
    if(result)
    {
        c = cOne;;
    } 
    else 
    {
        c = cOther;;
    }
    
    c.add(foo);
    

    首先,我不喜欢调用,也不喜欢将值赋给临时变量(test(foo)调用),原因有两个:

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

    第二,我不喜欢代码,如果你模糊了你的眼睛,它看起来是一样的。如果你的眼睛“模糊”的话,加上(foo)和cother.add(foo)“看起来”是一样的。例如,如果您将其更改为列表,并使用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;
    }
    

    本质上,我为块内的任何内容创建了一个方法,如果它有意义的话(通常是这样)。我喜欢有很多小方法。

        5
  •  1
  •   Ether    15 年前

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

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

    三种不同的引用中哪一种导致了NPE? obj1 ,请 obj2 obj1.getValue() 有时可能通过前面代码中的推理来解决问题,但不一定总是

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

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

    VS

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

    大多数人会认为条件句更容易理解,而且肯定更简洁。

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

        6
  •  1
  •   Ether    15 年前

    用于此目的的条件运算符非常罕见,因此眼睛实际上并不寻找它。

    我喜欢我的Java代码看起来是一致的,这样我和将来的维护者可以很容易地发现像分支一样的东西,太多的复杂性等等。因为我在别处使用IFS,我通常可以通过使用有条件的方法来吸收它。

    如果我使用的是一种通过表达式(比如python)进行很多“技巧”的语言,那就另当别论了。

        7
  •  0
  •   Dominik Sandjaja    15 年前

    imho“完整的”,长版本是一个有点可读性和肯定更好的长期维护。

        8
  •  0
  •   Ether    15 年前

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

    或者换句话说:如果您习惯于Perl,那么您可以很容易地阅读它。

        9
  •  0
  •   Ether    15 年前

    除了Matt B所说的,当您决定使用条件运算符时,您可以进一步使用此格式:

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

    它给代码更多的if-else感觉,并使其更容易阅读。