Search code examples
javatry-with-resources

Using try-with-resources with System.in


So my IDE is complaining if I don't enclose the Scanner in a try with block, but if I do it this way instead of closing it when it's supposed to close (once win = true), it closes the System.in stream, how do I prevent that?

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);
}

Solution

  • I would recommend against having multiple Scanner objects wrapping around the same input stream. (in this case, System.in) The reason for this is because Scanners may consume and buffer data from the underlying stream. This means that in some cases data can be lost. You can read more about it in this question.

    You might be able to get away with it here, in which case you should just not close the Scanner object by not wrapping it in a try-with-resources. In that case, you can suppress the warning with @SuppressWarnings("resource"). However, this is bad practice.

    Instead, I'd recommend creating a single global Scanner object that wraps around System.in, and then passing it to this method as a parameter instead of creating a new scanner in each method that requires input.