web-dev-qa-db-ja.com

Java-スキャナーとリソースリークを閉じています

私はJavaを学んでいて、楽しみのためにいくつかのプロジェクトに取り組んでいます。私が遭遇した1つの問題は、Scannerオブジェクトを使用するとEclipseが警告することです:

リソースリーク:「スキャン」は決して閉じられません。

そこで、コードの最後にscan.close();を追加し、警告を処理します。

同じパッケージ内にスキャナーオブジェクトも使用する他のクラスがあり、Eclipseはそれらのクラスのスキャナーをそれぞれ閉じるように指示しているため、問題が発生します。ただし、そのようにすると、スキャナーオブジェクトがすべて閉じられ、実行時にエラーが発生するようです。

エラーの原因の例を次に示します。

_import Java.util.Scanner;
public class test2 {
    public static void main(String [] args) {
        Scanner scan = new Scanner(System.in);
        int test = 0;
        do {    
            //Do stuff
            test = scan.nextInt();
            System.out.println(test);

            scanTest scanTest = new scanTest();
            scanTest.test();
        } while (test != 0);

        scan.close();       
    }
}

import Java.util.Scanner;
public class scanTest { 
    public void test() {
        Scanner scanner = new Scanner(System.in);
        int blah = scanner.nextInt();
        System.out.println(blah);
        scanner.close();
    }
}
_

スキャナーがscanTestクラスで閉じられ、_test2_のdoループに再び入ると、test = scan.nextInt();の行でエラーが発生します

スキャナーオブジェクトの作成をdoループに移動して、毎回新しいオブジェクトを作成しようとしましたが、それでもエラーが発生します。

これがなぜ起こっているのか、または問題が発生することなくすべてのI/Oオブジェクトが確実に閉じられるようにする方法がわかりません。

出会ったある投稿で、_System.in_を閉じると再び開くことはできないと述べました。この場合は、プログラムの最後でSystem.inのスキャナーオブジェクトが閉じられていることを確認し、他のクラスの他のスキャナー警告をすべて@suppressする必要がありますか?それとも、それらすべてのスキャナーオブジェクトを開いたままにしますか(悪い)?

11
SuperCow

まず、これはメモリリークではありません。

次に、ストリームラッパーを閉じると、デフォルトの実装では、ラップするストリームを閉じます。これは、スキャナーを(書かれているとおりに)初めて閉じるときに、はい、System.inを閉じることを意味します。

一般に、System.inから再度読み取る意味がある場合は、System.inを閉じないようにします。これを行う最善の方法は、プログラムによって異なります。

System.inからある種のバッファーに情報をコピーしてから、そのバッファーをスキャンすることができます。スキャナーを閉じず、他の場所で再利用する可能性があります。ガベージコレクションのためにスキャナーの参照を解除し、System.inに複数の新しいスキャナーを作成することもできます。

これらのソリューションはすべて同等ではなく、一部は他よりもはるかに優れていると考えられています。しかし、それはすべて呼び出しプログラムに依存します。いくつか試してみて、問題が発生した場合は、新しいStackOverflowの質問を開いて、コードの関連部分、問題の説明、入力例、および間違った出力(必要な出力とともに)を表示してください。

幸運を。

4
Edwin Buck

はい、スキャナーを閉じると、基になるストリーム(この場合はSystem.in)が閉じられます。これを回避するには、すべてのクラスで使用できるスキャナーのグローバル変数を作成するか、スキャナーをシャットダウンするための中心点を設定します(プログラムが終了する直前が理想的です)。

3
Scary Wombat

すべてのスキャナーに同じ名前を付けないでください。あなたがこのように複数のものを持っている場合:

_import Java.util.Random;
import Java.util.Scanner;

public class DayThree {

    public static void main(String[] args) {

        **Scanner textScanner = new Scanner(System.in);**

        // boolean operands 
            //    String(or objects)   .equals()      "this".equals("that")     false
            //    primitive data types     ==          'a'=='a'   ->  true   5==6   false
            //                             !=          'a'!='a'   ->  false  5!=6   true
            //                             !            !(true)   ->  false   !(false)   true
            //                             >            5 > 4     -> true    'a' > 'b'  false
            //                              <           5 < 4     -> false
            //                              <=          
            //                              >=    
            //       &&     ->  and        5 < 6 &&  7 > 10   -> false
                        // if either side of and is false the outcome is false
            //       ||     ->  or        5 < 6  || 7 > 10     -> true
                        // if either side of or is true  the outcome is true
        //System.out.println(!(5 < 10) && (7>3) ||  (true && false || true));

        /*     <-- this is a multi line comment
            System.out.println("What is the most amazing show on tv this week? ");
            String show = textScanner.nextLine().toLowerCase();  //this is case sensitive

            show = show.toLowerCase(); // changes the strng to a lowercase version
            show = show.toUpperCase(); 

            if(show.equalsIgnoreCase("game of thrones")){ // .equalsIgnoreCase( ignores caps/lower)
                System.out.println("Yes it is!");
            }
            else{
                System.out.println("You are wrong.");
                System.out.println(show + " is clearly inferior to Game of Thrones.");
            }

            System.out.println("Who is your favorite character in " + show + ".");
            String character = textScanner.nextLine().toLowerCase();

            if(character.contains("dragon")){
                System.out.println("CGI magic is so cool!");
            }
            else if(character.contains("lanister")){
                System.out.println("Wrong house.");
            }
            else{
                System.out.println(character + "is pretty cool I guess...");
            }
        */ 
//      asdf      alternate multi line comment use ctrl + /  on highlighted text. 
//                      doing this a second time undoes the comment 
//      sdaf
//      asdf
//      asdf
//      asdf

//      1.  ask about favorite something (pet)
//      2. save that into a string all lowercase
//      3. have a series of if else (x3) and else statements about the something

        //NOTE: DO NOT END CONDITIONALS WITH ; example: if(boolean);  IS WRONG. 
        **Scanner numScanner = new Scanner(System.in);** // the variable tells you what to use it for
        Random Rand = new Random();  // this makes a new random object 
        System.out.println("Pick a number.");
        int num = numScanner.nextInt();
        int sNum = Rand.nextInt(9) + 1;  // gives me a random num between 1-10
                                        // nextInt(bound)gives you a num from 0-bound
                                        //adding one gives you a num from 1 - bound + 1
        if(num > sNum){
            System.out.println("Too high");
            System.out.println("The number was " + sNum);
        }
        else if(num < sNum){
            System.out.println("Too low");
            System.out.println("The number was " + sNum);
        }
        else{
            System.out.println("Wow are you psychic? ");
        }
        textScanner.close();
        numScanner.close();
    }//main method

}
_

スキャナーごとに*scanner name goes here*.close();を配置します。すべて同じ名前の場合は、他のスキャナーとは異なる処理を行うものを変更します。

0