在 System.in 中使用 try-with-resources [重复]

Posted

技术标签:

【中文标题】在 System.in 中使用 try-with-resources [重复]【英文标题】:Using try-with-resources with System.in [duplicate] 【发布时间】:2020-12-11 20:06:09 【问题描述】:

所以我的 IDE 会抱怨如果我没有将 Scanner 包含在 try with 块中,但是如果我这样做而不是在它应该关闭时关闭它(一旦 win = true),它会关闭系统。在流中,我该如何防止呢?

public final void turn() 
    System.out.println("Enter your next move!");
    try (Scanner keyboard = new Scanner(System.in)) 
        final String move = keyboard.nextLine();
        if (move.isEmpty()) 
            won = true;
            return;
        
        if (!validateFormat(move)) 
            System.out.println("Invalid format, try again.");
            return;
        
        String[] moveAr;
        try 
            moveAr = move.split(",");
         catch (PatternSyntaxException e) 
            System.out.println(e.getMessage());
            return;
        
        try 
            validFields(moveAr);
         catch (InvalidTurnException e) 
            System.out.println(e.getMessage());
            return;
        
        final char colour = spielFeld.getField(getColumn(moveAr[0].charAt(0)),Character.getNumericValue(moveAr[0].charAt(1)) - 1).getColour();
        for (final String string : moveAr) 
            final int line = Character.getNumericValue(string.charAt(1)) - 1;
            final int column = getColumn(string.charAt(0));
            spielFeld.cross(column,line);
            final int columni = getColumn(string.charAt(0));
            if (spielFeld.columnCrossed(columni)) 
                points += crossedValues(string.charAt(0));
            
        
        if (spielFeld.colourComplete(colour)) 
            points += COLOUR_POINTS;
            coloursCrossed++;
        
        if (coloursCrossed >= 2) 
            won = true;
        
    
    System.out.println("Momentane Punkte: " + points);

【问题讨论】:

这能回答你的问题吗? Close Scanner without closing System.in 我在谷歌搜索中看到了这个,但想也许会有更好的解决方案?当然,为我认为是常见问题的问题创建自己的课程并不是唯一的解决方案。 我同意这并不理想,但它似乎是唯一的解决方案(考虑到您想彻底关闭资源)。您当然可以通过将防止关闭的包装类移动到单独的文件或使用库解决方案来保持代码更清洁,就像 here 所做的那样。我认为这是 JDK 中的一个设计缺陷,close'ing 流通常会在其包装的流上调用 close @Reizo “考虑到你想彻底关闭你的资源”。除了 System.in 不属于你,所以你不应该“干净地关闭”它,即使你把它包裹在什么东西里,比如 Scanner @Reizo 包装流关闭底层流的事实当然不是设计缺陷。如果他们不这样做,您将无法创建像new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)))) 这样的链式流,像这样手动或使用其中一些类提供的便利助手。 close() 在所有情况下都必须调用,除非在包装 System.in 时。让这成为例外,并非所有其他时间都使用包装器。 【参考方案1】:

我建议不要让多个 Scanner 对象环绕同一个输入流。 (在这种情况下,System.in)这是因为扫描程序可能会消耗和缓冲来自底层流的数据。这意味着在某些情况下数据可能会丢失。你可以阅读更多关于它的信息in this question。

您也许可以在这里侥幸逃脱,在这种情况下,您不应该通过不将 Scanner 对象包装在 try-with-resources 中来关闭它。在这种情况下,您可以使用@SuppressWarnings("resource") 取消警告。但是,这是不好的做法。

相反,我建议创建一个环绕 System.in 的单个全局 Scanner 对象,然后将其作为参数传递给此方法,而不是在每个需要输入的方法中创建新的扫描器。

【讨论】:

扫描器应该在每个周期接收一个新的流,所以我认为将其设为全局不会正常工作,那么它什么时候会要求输入? @NinjaNinjaNinja 您可以随时要求输入。您的代码看起来基本相同,但不是创建新的 Scanner 对象,而是接受它作为参数。如果您在每个循环中创建一个新的 Scanner,它仍然会包装相同的底层输入流。通过创建一个全局扫描器对象,您只需将其包裹一次,您就可以随时从System.in 获取数据。【参考方案2】:

如何防止这种情况发生?

不要关闭 Scanner 对象,即不要在包装 System.inScanner 上使用 try-with-resources。

相反,接受警告并将其隐藏,因为它是正常“资源”规则的一个特殊例外:

@SuppressWarnings("resource")
Scanner keyboard = new Scanner(System.in);

仅供参考:我正在使用 Eclipse IDE,它“使用 try-with-resources 环绕”只是修复警告的第一个选项:

【讨论】:

这是给学校的,我必须修复我的 IDE 给我的所有警告。

以上是关于在 System.in 中使用 try-with-resources [重复]的主要内容,如果未能解决你的问题,请参考以下文章

尝试转让所有权

在 System.in 中使用 try-with-resources [重复]

从 Java 中读取 System.in 的最快方法是啥?

为 System.in 设置环境

Access the Security System in Code 在代码中访问安全系统

在阅读之前清除/清除System.in(stdin)