Home > Mobile >  Java closing the scanner but still an error
Java closing the scanner but still an error

Time:11-21

Im fairly new to java and I wanted to create a BPM to Millisecond convertor for my guitar delay pedal as just a fun little side project. I know you should always close your scanner once you are done using it but my code will not work if it is closing.

public static void main(String[] args) {
ms_calc();
}

    public static void ms_calc () {
        Scanner scanbpm = new Scanner(System.in);
        System.out.println("What is your BPM?");
        int bpm = get_user_int (scanbpm,1,2300);
        double mS1 = Math.round((bpm*100)/6)*4;  
        double mS2 = Math.round((bpm*100)/6)*2; 
        int mS1R = (int)mS1;//casting doubles as ints
        int mS2R = (int)mS2;
        System.out.println("____________________________________");
        System.out.println();
        System.out.println("Whole : "   mS1R   " ms");
        System.out.println();
        System.out.println("1/2 : "   mS2R  " ms");
        for (int X = 1; X < 9; X = X * 2) {
            double mS = Math.round((60000.00/X)/bpm);
            int Y = X * 4;
            int mSR = (int)mS;
            System.out.println();
            System.out.println("1/"  Y   " : "  mSR  " ms");
        }
    
        System.out.println("____________________________________");
        System.out.println();
                scanbpm.close();
        main(null);
    }
    
    public static int get_user_int(Scanner scan, int min, int max) {
        int user_input  = min - 1;        
        boolean keep_asking = true;//boolean to regulate the while loop        
        while(keep_asking || user_input < min || user_input > max) { 
            try {//try this code not sure it's going to work
                user_input=scan.nextInt();
                keep_asking = false;
            }catch(Exception e) { 
                System.out.println("Invalid input.");                 
            }finally {
                scan.nextLine(); 
            }            
        }
        System.out.println(user_input);
        return user_input;
    }

The get_user_int was made in class and work in every other project I have made. Eclipse runs an error on line 1651 saying no line found. My only guess is that it would have to be something with the main(null); but I have a scanner and main(null); running in the same method and it works fine there.

CodePudding user response:

I know you should always close your scanner once you are done using it

No, this is entirely incorrect. You should NOT close the scanner.

The problem is: Resources should be closed, however, there is one particular kind of object, called a 'filter resource', which is sort of half a resource and half not. Hence, 'should the code close it' is a difficult question that automated linting tools generally cannot properly answer. Unfortunately, they try, and therefore, sometimes get it wrong. This is one of those cases.

filter streams 'wrap' an actual resource. For the purposes of avoiding running out of OS-level file handles and the like, they do not themselves contain any such things so they don't need to be closed (however, the thing they wrap is likely to be a system resource that should be). Filters can (and usually do) cache values, so you do need to at least flush them - and closing them flushes them, so in general it's just more convenient to close the filterstream (which also closes the underlying data stream), and the tools in your IDE that mark off that you're failing to properly close a resource prefer not to have to bother with drawing a difference between read ops (Stream) and write ops. 'flush the line' obviously does not apply to read ops.

Getting back to true resources (the things that a Scanner would wrap) - there is such a thing as who is responsible for closing it. Which is: The one who made it.

You did not make System.in -- therefore, you must not close it. Therefore, if you have a filterstream that you made that wraps around a stream you did not make, you shouldn't close that either.

Conclusion: new Scanner(System.in) must not be closed. Yes, it is highly unfortunate that IDEs mess up and sometimes overzealously tell you you should. You should never close System.in unless you specifically require this because you are implementing a tool that uses 'closing sysin' as a signal to the process that feeds data to yours, a messaging mechanism that is not recommended at all.

A few further notes on your code:

  • In java, we writeMethodNamesLikeThis, not_like_this. We write locals the same way (so, x, not X). The langspec doesn't require you do this, but all tutorials and 99.99% of java programmers do it that way. Not following suit means everybody will get confused reading your code and code you read or work on written by others confuses you.
  • Calling main(null) means you set up a recursive process that never ends. Enough loops and your code will crash with a StackOverflowError (wanna test it? Temporarily replace the .nextInt() call in your getUserInput method with returning a constant and remark out the .nextLine() line, run it, and watch it explode after a few thousand loops). The proper way to render a main menu that repeats is to use a while loop or do {} while loop, not to invoke your own method.
  • To ensure a thing is closed, you'd use try-finally the way you do in your getUserInput method, or, there's a simpler construct for this:
try (Scanner s = new Scanner(System.in)) {
  // code using 's' here
}

This generates code such that, no matter how code exits this block (via return;, by break; ing a loop that wraps around this code, or by throwing an exception, or by just running to the end and 'falling out', doesn't matter) - s.close() is called. Now, you should not do this to this code as scanner should not be closed, but for next time you open a real resource that really does require closing, that's how you do it. You don't resource.close(); at all, you use try-with, as above.

CodePudding user response:

Encapsulate both methods in one public class.

Rename ms_calc method name to main.

&

remove main(null) line. and you are good to go.

  • Related