vscode: in “while ((inputLine = in.readLine()) != null)”-loop.x = x + a 没有警告。Versus: x += “未使用局部变量的值”

vscode: in "while ((inputLine = in.readLine()) != null)"-loop. x = x + a without warning. Versus: x += a "value of the local variable is not used"

提问人:questionto42 提问时间:7/12/2020 最后编辑:questionto42 更新时间:4/22/2021 访问量:273

问:

以下是 https://docs.oracle.com/javase/tutorial/networking/urls/readingURL.html 中的一个示例,唯一的变化是将 String inputLine 的内容添加到 strAll String 中,而不是打印它,请参阅X_HERE。

import java.net.*;
import java.io.*;

public class URLReader {
    public static void main(String[] args) throws Exception {

        URL oracle = new URL("http://www.oracle.com/");
        BufferedReader in = new BufferedReader(
        new InputStreamReader(oracle.openStream()));

        String inputLine;
        String strAll = "";
        while ((inputLine = in.readLine()) != null)
            // System.out.println(inputLine);
            strAll = strAll + inputLine; // X_HERE
        in.close();
    }
}

这不会发出任何警告。如果将行 X_HERE 替换为

strAll += inputLine;

使用“加法分配”时,您会收到警告:

不使用局部变量 strAll 的值

如果将 while 条件替换为 (true),则 strAll 的警告将消失。为什么在这种情况下对“加法分配”的处理方式不同?

编辑感谢@Joni:我正在使用 Visual Studio Code,警告出现在“问题”窗口中。

java visual-studio-code while 循环 编译器警告赋 值运算符

评论

1赞 Joni 7/12/2020
您在哪里看到此警告?
0赞 questionto42 7/12/2020
@Joni Visual Studio Code - “问题”视图中出现警告。

答:

3赞 WJS 7/12/2020 #1

下面是一个更简单、孤立的相同效果的实例。

这两种变体都编译为相同的字节码。

在此示例中,

a += 1;

IDE 看到 1 更新,但没有看到 的直接用法。aa

在此示例中,

a = a + 1;

IDE 看到在表达式中使用,然后分配回 ,因此从 IDE 的角度来看,已被使用。aa + 1aa

仅仅为变量赋值并不构成使用。

请注意,此行为也存在于 中,但如果需要,可以禁用。unusedEclipse IDE

评论

0赞 questionto42 7/12/2020
这种差异在这样的循环中突然出现,其中加法赋值添加了一个变量,该变量是 while 条件的一部分?因为这是微小但惊人的差异:以 (true) 为条件,当使用 += 加法赋值时,strAll 没有警告。否则我当然明白你的意思,但这不可能是整个故事。或者你的观点也已经解释了这一点?
3赞 Joni 7/12/2020 #2

此警告不是 Java 语言的一部分,甚至不是 Java 编译器的一部分。这只是 Visual Studio Code 试图提供帮助。

这是 vs code 中静态代码分析功能中的一个 bug 或限制。它算作变量的“使用”,而不算作变量的“使用”。如果代码分析更智能,它将在这两种情况下都给出“未使用的变量”警告。strAll = strAll + inputLinestrAllstrAll += inputLine

评论

0赞 questionto42 7/12/2020
该问题的副本现在是 github.com/redhat-developer/vscode-java/issues/1518 上的一个问题
0赞 questionto42 7/12/2020
这也可能是我正在使用的OpenAdoptJDK的问题,我在github问题中提到了这一点。无论谁可能在 vscode 中检查上述代码示例的警告,使用 OracleJDK 进行测试都将有助于排除 OpenAdoptJDK 作为原因。
1赞 Stephan Herrmann 4/22/2021 #3

为了完整起见,这是我对 github 问题的回答:

strAll += inputLine是“复合赋值表达式”。因为这是 Java 的内置结构,所以 ecj(用于 vscode 的 Eclipse 编译器)知道这个结构的细节,特别是它跟踪隐式读取不会创建从另一个变量或参数到另一个变量或参数的数据流。strAll

strAll = strAll + inputLine然而,这只是无数形式中的一种,人类读者很容易看到它真的无处流动。strAll

虽然区别对待这两种形式的决定是在我加入 Eclipse 之前做出的,但我很确定团队认为这是 ecj 可以推理的事情和过于复杂的事情之间最清晰的界限。扩展流量分析时需要讨论的内容的一些示例:

  • strAll = "foo" + strAll + "bar";
  • strAll = (bar = strAll) + "foo";
  • strAll = convert(strAll); 这个比第一眼看起来更棘手
  • 等等。

所以模式可能是 ecj 给你一根手指,人们会拿走整个手臂,或者更多......

底线:如果您想向 Java 编译器提供更多信息,请适当地使用 Java 细节:)复合赋值比其长形式传达的信息更多。

关于,我认为(无需仔细观察),当发现方法无法正常完成时,流分析就会停止。while (true)