改变if语句中的状态是不好的做法吗?

时间:2009-11-25 22:31:17

标签: java if-statement state

我写了一些类似于以下内容的代码:

String SKIP_FIRST = "foo";
String SKIP_SECOND = "foo/bar";

int skipFooBarIndex(String[] list){
    int index;
    if (list.length >= (index = 1) && list[0].equals(SKIP_FIRST) ||
        list.length >= (index = 2) && 
        (list[0] + "/" + list[1]).equals(SKIP_SECOND)){
        return index;
    }

    return 0;
}

String[] myArray = "foo/bar/apples/peaches/cherries".split("/");
print(skipFooBarIndex(myArray);

这通过分配索引来更改if语句内部的状态。但是,我的同事非常不喜欢这个。

这是一种有害的做法吗?有什么理由这样做吗?

14 个答案:

答案 0 :(得分:15)

是。这显然降低了可读性。以下代码有什么问题?

int skipFooBarIndex(String[] list){
    if(list.length >= 1 && list[0].equals(SKIP_FIRST)) 
        return 1;
    if(list.length >= 2 && (list[0] + "/" + list[1]).equals(SKIP_SECOND))
        return 2;
    return 0;
}

理解起来要容易得多。一般来说,不鼓励在表达式中产生副作用,因为你将依赖于子表达式的评估顺序。

假设你把它算作“聪明”的代码,那么永远记住Brian Kernighan的话是很好的:

  

调试是第一次编写代码的两倍。因此,如果您尽可能巧妙地编写代码,那么根据定义,您不够聪明,无法对其进行调试。

答案 1 :(得分:4)

  

......但是,我的同事非常不喜欢这个......

是的,确实如此。不仅仅是因为你可以这样编码,你必须这样做。

请记住,这段代码最终必须由某人维护(有人可能在8个月内成为您的自己)

更改if中的状态,make更难阅读和理解(主要是因为它不常见)

引用Martin Fowler:

  

任何傻瓜都可以编写计算机可以理解的代码。优秀的程序员编写人类可以理解的代码

答案 2 :(得分:2)

有一个很好的理由不这样做:这会让你的代码真的难以理解和推理。

答案 3 :(得分:2)

问题是代码会在代码审查会话中生成多个WTF。任何使人们“等待,什么?”的东西。必须离开。

即使在易于阅读的代码中,创建错误也很容易。没理由让它更容易。

答案 4 :(得分:1)

是的,在查看代码时很难遵循副作用。

关于这样做的理由:不,没有真正的理由去做。我还没有偶然发现一个if语句,如果没有副作用就不能重写而不会有任何损失。

答案 5 :(得分:1)

唯一不对的是它对于没有写它的人来说是不熟悉和困惑的,至少在他们弄清楚的时候会有一分钟。我可能会这样写它以使其更具可读性:

if (list.length >= 1 && list[0].equals(SKIP_FIRST)) {
    return 1;
}

if (list.length >= 2 && (list[0] + "/" + list[1]).equals(SKIP_SECOND)) {
    return 2;
}

答案 6 :(得分:1)

借鉴cppreference.com

与运算符优先级相关的C ++的一个重要方面是评估的顺序和表达式中副作用的顺序。在某些情况下,事物发生的顺序没有定义。例如,请考虑以下代码:

float x = 1;
x = x / ++x;

x的值不能保证在不同的编译器中保持一致,因为不清楚计算机是否应该首先评估除法的左侧或右侧。根据首先评估哪一方,x可能采用不同的值。

此外,虽然++ x的计算结果为x + 1,但实际将该新值存储在x中的副作用可能会在不同的时间发生,从而导致x的值不同。

最重要的是,像上面这样的表达方式非常模糊,应该不惜一切代价避免。如有疑问,请将单个模糊表达式分解为多个表达式,以确保评估顺序正确。

答案 7 :(得分:1)

  

这是一种有害的做法吗?

绝对是的。代码很难理解。除了作者之外,任何人都需要两到三次读取。任何难以理解且可以用更简单的方式重写的代码都应该以这种方式重写。

你的同事是绝对正确的。

  

有没有理由这样做?

这样做的唯一可能原因是你已经对应用程序进行了广泛的分析,并发现这部分代码是一个重要的瓶颈。然后你实现了上面的憎恶,重新运行探查器,发现它真的提高了性能。

答案 8 :(得分:0)

好吧,我花了一些时间阅读上面的内容,却没有意识到发生了什么。所以我肯定会建议它不理想。我不会永远期望if()语句本身改变状态。

答案 9 :(得分:0)

我不建议在没有充分理由的情况下具有副作用的if条件。对我来说,这个特殊的例子花了几个时间来弄清楚发生了什么。虽然我当然无法想到一个,但可能会有一个不太糟糕的情况。

答案 10 :(得分:0)

理想情况下,每段代码都应该做一件事。让它做不止一件事可能会令人困惑,令人困惑的是你在代码中不想要的东西。

if语句条件中的代码应该生成一个布尔值。通过分配值来处理它会使它做两件事,这通常很糟糕。

此外,人们期望条件只是条件,当他们得到代码正在做什么的印象时,他们经常会浏览它们。在他们决定需要之前,他们不会仔细解析所有内容。

坚持在我正在审核的代码中,我会将其标记为缺陷。

答案 11 :(得分:0)

在C中,在if语句中更改状态是相当常见的。一般来说,我发现在可接受的地方有一些不成文的规则,例如:

  • 您正在读取变量并检查结果:

    int a;
    ...
    if ((a = getchar()) == 'q') { ... }
    
  • 递增值并检查结果:

    int *a = (int *)0xdeadbeef;
    ...
    if (5 == *(a++)) { ... }
    

当它不可接受时:

  • 您正在为变量分配常量:

    int a;
    ...
    if (a = 5) { ... } // this is almost always unintentional
    
  • 混合搭配pre- and post-incrementshort-circuiting

    int a = 0, b;
    ...
    if (b || a++) { ... }    // BAD!
    

由于某种原因,我试图标记为代码的部分的字体在SO上不是固定宽度,但是在固定宽度字体中,有些情况下if表达式内的赋值既明智又清晰。

答案 12 :(得分:0)

您还可以获得三元以避免多次退货:

int skipFooBarIndex(String[] list) {
    return (list.length > 0 && list[0].equals(SKIP_FIRST)) ? 1 :
       ((list.length > 1 && (list[0] + "/" + list[1]).equals(SKIP_SECOND)) ? 2 : 0);
}

虽然这个例子不太可读。

答案 13 :(得分:0)

作为执行大量维护编程的人说话:如果我碰到这个,我会诅咒你,哭泣然后改变它。

像这样的代码是一场噩梦 - 它尖叫着两件事之一

  1. 我是新来的,我需要帮助做正确的事。
  2. 我觉得我非常聪明,因为我已经保存了代码行,或者我已经欺骗了编译器并使其更快。它不聪明,不是最优,也不好笑