【问题标题】:How to close a scanner without closing the underlying System.in?如何在不关闭底层 System.in 的情况下关闭扫描仪?
【发布时间】:2014-08-26 12:48:33
【问题描述】:

如果我关闭一个扫描仪对象并创建一个新对象并尝试读取更多输入,我将收到NoSuchElementException 异常。

我的代码工作正常,但如果我不关闭扫描仪,它会给我一个警告。但是,如果我关闭它以消除警告,我也会关闭 System.in... 我该如何避免这种情况?

另外,不关闭扫描仪有什么后果吗?

编辑:这是我的代码:

这是 NameAddressExists() 方法:

public void NameAddressExists() {
    System.out.println("Enter name");
    Scanner sc = new Scanner(System.in);
    String n = sc.next();
    System.out.println("Enter address");
    String a = sc.next();
    int flag = 0;
    for(int i = 0; i < count; i++) {
        if(array[i].name .equals(n) && array[i].address .equals(a)) {
            System.out.println("True");
            flag = 1;
        }
    }
    if(flag != 1) {
        new Agency(n, a);
    }
    sc.close();
}

这是 PanNumberExists() 方法:

public boolean PanNumberExists() {
    Scanner s = new Scanner(System.in);
    String n = "";
    System.out.println("Enter the 5 digits");
    try {
        n = s.nextLine();
    }catch(Exception e) {
        System.out.println(e);
    }finally {
        s.close();
    }
    if(n  .equals(this.PAN.subSequence(4,9))) {
        return true;
    }
    else {
        return false;
    }
}

这些方法是从以下 main() 方法调用的:

public static void main(String args[]) {
    Agency obj1 = new Agency("XYZ", "ABCD");
    Agency obj2 = new Agency("XYZ", "ABCDEFG", "+91083226852521", "ab 1234567", "abcd12345ab");
    // Agency obj3 = new Agency("XYZ", "TSRK", "36", "ab 1234567", "abcd12345ab");
    obj1.NameAddressExists();
    System.out.println(obj2.PanNumberExists());
}

如您所见,我首先调用 NameAddressExists() 方法,在该方法中我打开、使用和关闭名为 'sc' 的 Scanner。这工作正常,并给了我正确的输出。接下来,我调用 PanNumberExists() 方法,在该方法中我打开另一个名为 's' 的 Scanner 并尝试使用它从用户那里获取一些输入。这是我收到NoSuchElementException 异常的地方。如果我在 NameAddressExists() 方法中将 Scanner 'sc' 保持打开状态,则不会收到此错误。

【问题讨论】:

  • 还有其他问题,查看您的代码会使问题更容易诊断。
  • 这不是正常行为。你能显示你的代码吗?至于不关闭扫描仪——冒着被其他用户攻击的风险——如果你的程序不大,这没什么大不了的。但是最好关闭你打开的东西来管理内存。
  • 只需在程序最后的最后一个块中关闭扫描程序,您就可以了。
  • 另外,能否提供JDK版本和操作系统?

标签: java java.util.scanner nosuchelementexception system.in


【解决方案1】:
Scanner scan = new Scanner(new FilterInputStream(System.in) {
    @Override
    public void close() throws IOException {
        // do nothing here ! 
    }
});

或者,只需通过实现自定义装饰器来忽略close()

public class UnClosableDecorator extends InputStream {

    private final InputStream inputStream;

    public UnClosableDecorator(InputStream inputStream) {
        this.inputStream = inputStream;
    }

    @Override
    public int read() throws IOException {
        return inputStream.read();
    }

    @Override
    public int read(byte[] b) throws IOException {
        return inputStream.read(b);
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        return inputStream.read(b, off, len);
    }

    @Override
    public long skip(long n) throws IOException {
        return inputStream.skip(n);
    }

    @Override
    public int available() throws IOException {
        return inputStream.available();
    }

    @Override
    public synchronized void mark(int readlimit) {
        inputStream.mark(readlimit);
    }

    @Override
    public synchronized void reset() throws IOException {
        inputStream.reset();
    }

    @Override
    public boolean markSupported() {
        return inputStream.markSupported();
    }

    @Override
    public void close() throws IOException {
        //do nothing
    }
}

main()中使用时,

public static void main(String[] args) throws Exception {
        System.setIn(new UnClosableDecorator(System.in));
}

【讨论】:

    【解决方案2】:

    您可以使用装饰器模式并创建无法关闭的自定义InputStream,然后将其传递给Scanner

    import java.io.IOException;
    import java.io.InputStream;
    
    public class PreventClosingInputStream extends InputStream {
    
        private InputStream inputStream;
    
        public PreventClosingInputStream(InputStream inputStream) {
            this.inputStream = inputStream;
        }
    
        @Override
        public int read() throws IOException {
            return inputStream.read();
        }
    
        @Override
        public void close() throws IOException {
            // Don't call super.close();
        }
    
    }
    

    然后,在您的代码中:

    PreventClosingInputStream in = new PreventClosingInputStream(System.in);
    Scanner s = new Scanner(in);
    // ...
    s.close(); // This will never close System.in as there is underlying PreventClosingInputStream with empty close() method
    

    使用 try-with-resources:

    try (PreventClosingInputStream in = new PreventClosingInputStream(System.in);
            Scanner s = new Scanner(in);) {
        // ...
        // resources will be automatically closed except of System.in
    }
    

    【讨论】:

      猜你喜欢
      • 2023-04-05
      • 2011-05-20
      • 2014-06-29
      • 1970-01-01
      • 1970-01-01
      • 2013-02-18
      • 1970-01-01
      • 2015-03-19
      • 1970-01-01
      相关资源
      最近更新 更多