扫描仪在方法中从未关闭,但我认为它实际上会在每次方法结束时关闭?

Scanner is never closed in method, but I think it does actually close every time the method ends?

提问人:simo 提问时间:11/15/2022 更新时间:11/15/2022 访问量:119

问:

public static void maxintRecursive(int max) {

// create scanner
        Scanner in = new Scanner(System.in);

// asks user for integer input
        int a = in.nextInt();



// checks if integer input satisfies exit condition, closes scanner, prints max and returns
        if (a <= 0) {
            in.close();
            System.out.println("Max int is: " + max);
            return;
        }

// checks if input is greater than previous max registered int
        if (a > max) {
            max = a;
        }
// calls itself again
        maxintRecursive(max);
    }

我可以成功编译并运行它,但在第 3 行它下划线“in”表示它永远不会关闭 但是,此方法会不断调用自身,直到达到退出条件 (<=0) ,在此条件下,扫描程序实际上会关闭

这是一个错误吗?它实际上永远不会关闭并且我遇到内存泄漏吗?

我应该从主方法中传递扫描仪,还是相同?

此递归方法要求用户输入整数,并在用户输入 0 或更少时返回收到的最大整数

我在方法内部创建了一个扫描程序,并在递归方法达到其退出条件时将其关闭

我预计扫描程序会在退出条件下被我的代码关闭,但 VS Code 说它永远不会关闭

Java 递归 方法 java.util.scanner

评论

0赞 BarrySW19 11/15/2022
不知道为什么要使用递归方法执行此操作,但如果必须这样做,最好在调用方法之前在方法外部创建一个 Scanner,而不是在每次调用该方法时创建一个新的 Scanner。使用这种方法,您将有多个扫描仪都从 System.in 读取数据。

答:

0赞 Pshemo 11/15/2022 #1

每次调用方法时,它都会创建自己的局部变量。例如,如果您有像

void foo(int n) { 
    int x = n + 1; 
    if (x < 2) 
        foo(x); 
}

然后你像那样调用它,在执行时它将有自己的两个局部变量(方法参数)和(在方法主体中声明)。
然后,当您递归调用时,该调用将创建另一组局部变量,这些变量将保存值。
foo(0);n=0x = n+1 = 0+1 = 1foo(x);foo(1)nxn=1x=2

同样,在您的示例中,每次调用 method 时,它都会创建自己的单独对象。因此,如果您调用方法 N 次,则会创建 N 个 Scanner 对象(所有这些对象都从 中读取)。即使调用方法处理,它也只会关闭由递归调用创建的 Scanner。在以前的方法调用中创建的其他扫描程序永远不会关闭。maxintRecursiveScanner in = new Scanner(...)System.inin.close();if (a <= 0)

可能的解决方案还可以在方法末尾添加(在递归调用之后),这将确保每个方法都将关闭自己的 Scanner。in.close();

首选的解决方案是首先防止创建如此多的扫描仪。相反,在方法中创建一个并将其作为参数传递给递归方法。由于它将被传递,因此 Java 不会强制您在方法本身中关闭该扫描程序,而是在创建它的范围内(主方法)中关闭该扫描程序。main

为此,您需要通过修改其声明(例如)来让 Scanner 接受其参数maxintRecursive

public static void maxintRecursive(int max, Scanner in) {
    //...
}

这样,您现在需要的只是类似的东西

public static main(String[] args){
    Scanner scanner = new Scanner(System.in);
    maxintRecursive(-1, scanner);
    scanner.close();
}

顺便说一句,我们避免创建在我们自己的方法中处理的 Scanner 的另一个原因是,通过该方法关闭此类 Scanner 也会关闭 。这意味着当您尝试再次调用您的方法时,它将创建 Scanner,它将尝试从已经关闭的 .同样,在这种情况下,首选解决方案是将扫描仪处理 System.in 作为方法参数传递System.inSystem.inSystem.in