0

Suppose I would like to add a method to Scanner called nextPositiveInt() which is similar to nextInt() except that when a negative integer is detected, a custom InputNegativeException is thrown.

Why would I want to do this when there are solutions that utilise hasNextInt()? While being a little less concise, it seems a whole lot tidier and more logical given the purpose of exceptions. For example:

Extended Scanner method:

Scanner cli = new Scanner(System.in);
boolean inputValid = false;

do
{
    System.out.println("Enter your age:");
    try
    {
        int age = cli.nextPositiveInt();
    }
    catch(InputNegativeException e)
    {
        System.out.println("You cannot specify a negative age.");
        inputValid = false;
    }
    catch(InputMismatchException e)
    {
        System.out.println("Your input must be numeric.");
        inputValid = false;
    }
} while(!inputValid);

hasNext() method:

Scanner cli = new Scanner(System.in);

do
{
    System.out.println("Please enter a positive number!");
    while(!sc.hasNextInt())
    {
        System.out.println("That's not a number!");
        sc.next(); // this is important!
    }
    int number = sc.nextInt();
} while(number <= 0);

So assuming you aren't already firing up a response telling me why this is a very bad idea (if it is, please do; I imagine there might be some objection regarding putting validation in Scanner) I'm confused about how to go about this. I guess I need to replicate the body of nextInt() in nextPositiveInt() with some minor changes? Can you even source the body of nextInt() anywhere?

I apologise that I have no code to show any effort I've made but I'm not sure where to start.

Community
  • 1
  • 1
underskor
  • 189
  • 11

2 Answers2

1

You cannot extend Scanner since it's final:

public final class Scanner
extends Object
implements Iterator<String>

What I would do is have a helper method in one of my classes:

public static int ensureNonNegative(int val) {
  if (val >= 0) {
    return val;
  } else {
    throw new InputNegativeException(val);
  }
}

and would use it like so:

int val = ensureNonNegative(scanner.nextInt());
NPE
  • 438,426
  • 93
  • 887
  • 970
  • I saw that in another question - so the only way would be to have a `nextPositiveInt` method somewhere else? Not ideal but would work I guess. – underskor May 23 '12 at 07:08
1

Althought Scanner class is final and you cann't extend it there exist another solution. You can use Delegation pattern.

Also as Scanner class has all nessasary methods public you can easily copy original method and make a little change. See source code of Scanner class the only thing you should change is regexp used for matching string in order to exclude negative ints.

Source code of scanner:

public int nextInt() {
    return nextInt(defaultRadix);
}

public int nextInt(int radix) {
    // Check cached result
    if ((typeCache != null) && (typeCache instanceof Integer)
    && this.radix == radix) {
        int val = ((Integer)typeCache).intValue();
        useTypeCache();
        return val;
    }
    setRadix(radix);
    clearCaches();
    // Search for next int
    try {
        String s = next(integerPattern());
        if (matcher.group(SIMPLE_GROUP_INDEX) == null)
            s = processIntegerToken(s);
        return Integer.parseInt(s, radix);
    } catch (NumberFormatException nfe) {
        position = matcher.start(); // don't skip bad token
        throw new InputMismatchException(nfe.getMessage());
    }
}

You should change only:

String s = next(integerPattern());

For you purposes you can hardcode regexp. Original regexp can easily be caught on debug.

Definitely it wouldn't be the best solution in terms of realization - a lot of code to write and many copy-paste, but it would be easy and nice to use.

nhahtdh
  • 52,949
  • 15
  • 113
  • 149
Dmitry
  • 1,233
  • 11
  • 14