Asked  6 Months ago    Answers:  5   Viewed   54 times

I'm trying to make a small program more robust and I need some help with that.

Scanner kb = new Scanner(System.in);
int num1;
int num2 = 0;

System.out.print("Enter number 1: ");
num1 = kb.nextInt();

while(num2 < num1) {
    System.out.print("Enter number 2: ");
    num2 = kb.nextInt();
}
  1. Number 2 has to be greater than number 1

  2. Also I want the program to automatically check and ignore if the user enters a character instead of a number. Because right now when a user enters for example r instead of a number the program just exits.

 Answers

45

Use Scanner.hasNextInt():

Returns true if the next token in this scanner's input can be interpreted as an int value in the default radix using the nextInt() method. The scanner does not advance past any input.

Here's a snippet to illustrate:

Scanner sc = new Scanner(System.in);
System.out.print("Enter number 1: ");
while (!sc.hasNextInt()) sc.next();
int num1 = sc.nextInt();
int num2;
System.out.print("Enter number 2: ");
do {
    while (!sc.hasNextInt()) sc.next();
    num2 = sc.nextInt();
} while (num2 < num1);
System.out.println(num1 + " " + num2);

You don't have to parseInt or worry about NumberFormatException. Note that since the hasNextXXX methods don't advance past any input, you may have to call next() if you want to skip past the "garbage", as shown above.

Related questions

  • How do I keep a scanner from throwing exceptions when the wrong type is entered? (java)
Tuesday, June 1, 2021
 
Tapha
answered 6 Months ago
72

That's because the Scanner.nextInt method does not read the newline character in your input created by hitting "Enter," and so the call to Scanner.nextLine returns after reading that newline.

You will encounter the similar behaviour when you use Scanner.nextLine after Scanner.next() or any Scanner.nextFoo method (except nextLine itself).

Workaround:

  • Either put a Scanner.nextLine call after each Scanner.nextInt or Scanner.nextFoo to consume rest of that line including newline

    int option = input.nextInt();
    input.nextLine();  // Consume newline left-over
    String str1 = input.nextLine();
    
  • Or, even better, read the input through Scanner.nextLine and convert your input to the proper format you need. For example, you may convert to an integer using Integer.parseInt(String) method.

    int option = 0;
    try {
        option = Integer.parseInt(input.nextLine());
    } catch (NumberFormatException e) {
        e.printStackTrace();
    }
    String str1 = input.nextLine();
    
Tuesday, June 1, 2021
 
mgraph
answered 6 Months ago
93

The class java.io.Console may be useful:

System.console().readPassword();

This reads a sequence of chars from the console, without echoing anything. Note that it only works when you launch your java application with a real console. Otherwise, System.console() returns null.

Saturday, July 3, 2021
 
Uours
answered 5 Months ago
89

Use want = scan.next(); instead of nextLine().

The reason for your problem is that following the preceding nextInt(), you're still on the same line, and nextLine() returns the rest of the current line.

Here's a smallest snippet to reproduce the behavior:

Scanner sc = new Scanner(System.in);
System.out.println("nextInt() = " + sc.nextInt());
System.out.println("nextLine() = " + sc.nextLine());

When you type in, say, 5 and then hit Enter, the output is:

nextInt() = 5
nextLine() = 

That is, nextLine() did not block for your input, because the current line still has an empty string remaining.

For comparison, when you type in, say 5 yeah! and then hit Enter, then the output is:

nextInt() = 5
nextLine() =  yeah!

Note that " yeah!" actually comes from the same line as the 5. This is exactly as specified in the documentation:

String nextLine(): Advances this scanner past the current line and returns the input that was skipped. This method returns the rest of the current line, excluding any line separator at the end. The position is set to the beginning of the next line.


On half-open ranges

Assuming that the number to guess is between 1 and 10 inclusive, the following code is "wrong":

numRandom = rand.nextInt(9)+1; // this can only be in 1..9 range inclusive!

Here's an excerpt from the documentation of java.util.Random:

int nextInt(int n): Returns a pseudorandom, uniformly distributed int value between 0 (inclusive) and the specified value (exclusive)

That is, like a lot of methods in Java's API, Random.nextInt(int) uses the half-open range, with inclusive lower bound and exclusive upper bound.

Related questions

  • Are upper bounds of indexed ranges always assumed to be exclusive?
Thursday, August 12, 2021
 
j3d
answered 4 Months ago
j3d
76

The only workaround that I have found is one used back in .NET Framework 1.1.

As the InternalsVisibleToAttribute is not useable in .NET 2.0 Visual Basic, the only workaround that I have found is to include my tests within the same project as my library itself. Besides, some further work needs to be accomplished.

  1. Create yourself a new compilation CONFIG called "Tests" (that is where you may select "Release"/"Debug");
  2. Create a new folder named "Tests" within your project;
  3. Add a new class, the one to test your Friend (internal in C#) members;
  4. First line of code within this class should be: #if CONFIG = "Tests" then ... #end if;
  5. Place your code between this compiler IF directive.

For example, if I have the following Friend class:

Friend Class MyFactory
    Friend Property Property1 As Object
        Get
            Return _field1
        End Get
        Set (ByVal value As Object)
            _field1 = value
        End Set
    End Property

    Friend Sub SomeSub(ByVal param1 As Object)
        ' Processing here...
    End Sub
End Class

Then, if you want to test this class in .NET 2.0 Visual Basic, you will need to create a test class within the same project where the MyFactory class sits. This class should look like so:

#If CONFIG = "Tests" Then

    Imports NUnit.Framework

    <TestFixture()> _
    Public Class MyFactoryTests
        <Test()> _
        Public Sub SettingProperty1Test
            ' Doing test here...
        End Sub
    End Class

#End If

Since you have a compiler directive telling the compiler to compile and to include this class only when the "Tests" CONFIG is selected, you won't get this class on "Debug" or on "Release" mode. This class won't even be part of the library, this for not polluting your library unnecessarily, and this allows you to test your Friend class anyway.

That is the smartest way I have found to work around this issue in Visual Basic .NET 2.0.

Wednesday, November 24, 2021
 
TheFrack
answered 6 Days ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share