1

Accepting user input one character at a time, the largest acceptable integer before I have to limit input seems to be (10^8)-1. I was mildly surprised that it wasn't Integer.MAX_VALUE. Why isn't it?

Code written out in the Keyboard class that extends KeyAdapter:

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

public class Keyboard extends KeyAdapter{
    private final int MAX_TESTABLE = 99999999;
    private final int VK_NUMBER = 48; //ASCII 0 starts here
    private final int VK_NUMBERPAD = 96; //ASCII numberpad offset

    public void keyPressed(KeyEvent e){
        int key = e.getKeyCode();

        if(((char)key == '0' ||
            (char)key == '1' ||
            (char)key == '2' ||
            (char)key == '3' ||
            (char)key == '4' ||
            (char)key == '5' ||
            (char)key == '6' ||
            (char)key == '7' ||
            (char)key == '8' ||
            (char)key == '9')){
            if(Integer.parseInt(Launcher.inputString+(char)key) <= MAX_TESTABLE){
                Launcher.inputString += (char)key;
            }
        }else if (e.getKeyLocation() == KeyEvent.KEY_LOCATION_NUMPAD){
            if(Integer.parseInt(Launcher.inputString+(char)(VK_NUMBER+key-VK_NUMBERPAD)) <= MAX_TESTABLE){
                Launcher.inputString += (char)(VK_NUMBER+key-VK_NUMBERPAD);
            }
        }

        System.out.println(
            "Key "+key+" pressed\n"+
            "Input string: "+Launcher.inputString
        );
    }
}

Other classes linked here:

Reason
  • 105
  • 11
  • `parseInt` throws before you can compare it. – SLaks Nov 13 '16 at 02:50
  • 3
    Integer.parseInt("2147483647"); is the largest integer that can be parsed from a string and works fine for me. What is the value of `key` being added to the string? – Matthew Wright Nov 13 '16 at 02:52
  • 1
    Are you sure you aren't trying to parse `999 999 999` plus another digit at the end? – chrylis -cautiouslyoptimistic- Nov 13 '16 at 02:58
  • Voting not reproducible. – Sotirios Delimanolis Nov 13 '16 at 03:01
  • I have edited to include more code and the error message. Sotirios I'm semi-new to Stack Overflow. Could you explain what you think I need to do differently instead of voting me down? – Reason Nov 13 '16 at 03:04
  • Looks to me like Matthew's answer is what's going on. – Gulllie Nov 13 '16 at 03:06
  • What on earth is the purpose of `&& true` in the if condition? – Sнаđошƒаӽ Nov 13 '16 at 03:06
  • Sнаđошƒаӽ, that's just a placeholder I forgot to remove. I will try out Mathew's suggestion now. – Reason Nov 13 '16 at 03:11
  • Your exception is returning a value just under 10 billion, not 1 billion. 9999999999 -> 9,999,999,999. Everything is working like it should. – Matthew Wright Nov 13 '16 at 03:13
  • what is inputString?? – Hendrik T Nov 13 '16 at 03:16
  • Well-spotted Mathew. I was asking about the maximum I can **test** though. Another thing: if I test `if(Integer.parseInt(inputString) < 2147483647)` I still get an exception. Maybe because Integer.parseInt(inputString) can return a value that's too large? Not sure. I'm pretty new to Java. – Reason Nov 13 '16 at 03:21
  • As a new Stack Overflow user who has gotten a lot of help by reading other questions and very much would like to fit into this community, it's very frustrating that my question is getting so down voted. I would like to fix anything that makes my question bad but I don't see what I am doing wrong. Could someone explain why I'm getting so down voted? This is reproducible, unlike what Sotirios has said. :/ – Reason Nov 13 '16 at 03:30
  • If you pass in a value larger then 2147483647 to _Integer.parseInt()_, it will throw the exception before it can even compare it to _< 2147483647_, because you're already trying to assign a value to large for a Integer in your call to _parseInt()_. have a look at HopefullyHelpful's answer for an idea to get around this. – Gulllie Nov 13 '16 at 03:38
  • Thanks Gullie, I saw his answer and am trying to work it into my program now. I don't understand `.compareTo()` very well so it's taking some fiddling. I'll provide feedback when I can get a result. – Reason Nov 13 '16 at 03:40
  • Gullie, HopefullyHelpful's answer might not cover it; using `if(inputString.compareTo("500"+(char)key) <= 0)` seems to only test superficially in that it will allow any number starting with a value 1-4 through but not any value starting with 5-9. I cannot type "79" for example, but I can type "4,323". – Reason Nov 13 '16 at 04:09
  • See my answer, and let me know if that works. – Gulllie Nov 13 '16 at 04:11
  • Thanks Gullie, I have replied under your answer – Reason Nov 13 '16 at 04:27
  • @Hendrik T, I'm very sorry but I only just noticed I forgot to answer your question "what is inputString??" The variable `inputString` holds the user input from the keyboard. It can be subtracted from using `KeyEvent.VK_BACK_SPACE` and added to using characters corresponding to numbers. – Reason Nov 13 '16 at 04:30
  • After a fair bit of head-scratching and looking around, I found the answer I was looking for. I would like to make this thread useful to anyone with the same question, but I don't have enough reputation to answer my own questions yet. Here is my answer: http://pastebin.com/bq3vYZe4 Essentially a mix of what everyone has said, plus a little bit more highlighted in bold. If someone pastes this in as an answer, I will gladly accept it. Just trying to be a good part of the community here. – Reason Nov 13 '16 at 21:27
  • Edit to my own linked answer: it seems that I have to go **2 orders of magnitude** down - not 1. Not sure what I missed. **Maybe someone can answer my question.** – Reason Nov 13 '16 at 22:51
  • @Vaysym Great to hear you found an answer. If you don't mind, I'll paste it into my answer to make it easier to find in case someone comes along with a similar question. :) – Gulllie Nov 14 '16 at 03:02

4 Answers4

1

EDIT: Here is what ended up being the solution, as found by Vaysym. I'm pasting it here to make it easier for anyone in the future who might look this up:

The answer is in the question: (10^8)-1

Here's why:

In Java, the primitive type int is allowed 4 bytes of memory: 2^32. Because it is signed, we have to allocate half of the 32 bits for the negative spectrum. We also have to subtract one from the total (which, because it's an odd number, happens to actually subtract from the positive spectrum). So our total range becomes (2^(32-1))-1 = 2,147,483,647

Because we are testing USING int here, this is the maximum testable number. So on the right operand the most we can check for is (2^31)-1, so we get this code: if(Integer.parseInt(inputString+(char)key) < 2147483647){}

This will still throw an exception because the left operand can end up being higher than Integer.MAX_VALUE, so we have to limit inputString before it gets there. Because the input is received one character at a time and the largest digit you can input, 9, is greater than the left-most digit of (2^31)-1, which is a 2, the closest we can get to Integer.MAX_VALUE is an entire order of magnitude short; Integer.MAX_VALUE has 10 digits, so we cannot test further than 9 digits: (10^(10-1))-1 = (10^9)-1 = 999,999,999

Because we're testing inputString plus the next inputted digit, we have to go down another order of magnitude, bringing us to the final answer of (10^8)-1

Final code: if(Integer.parseInt(inputString+(char)key) < 999999999){}

--------------------

Original answer:

The problem with how you're using Integer.parseInt is (quoted from my comment):

If you pass in a value larger then 2147483647 to Integer.parseInt(), it will throw the exception before it can even compare it to < 2147483647, because you're already trying to assign a value to large for a Integer in your call to parseInt().

The exception will be thrown if you pass in anything other then a number under 2147483647, including an empty String.

To get around this, try using a try-catch block:

        try
        {
            Integer.parseInt(inputString);
            //No exception thrown, this is a valid Integer!
        }
        catch(NumberFormatException e)
        {
            //NumberFormatException! "inputString" Can not be an Integer!
        }

If an exception is thrown by Integer.parseInt(), the code in the catch block will run, otherwise the code in the try block will continue running. By catching the exception, it won't cause your program to crash.

If you don't want to use try/catch, you'll just have to limit what the user can type. You can use Long and parseLong instead of Integer to allow larger numbers, but that will still throw an exception if you enter a non-number.

Update: You could use this to check if input string will fit into an Integer (if the number is smaller then a long, which it probably will be), but unfortunately it will still throw the exception if you enter something that isn't a number.

    if(Long.parseLong(inputString+(char)key) > 2147483647)
    {
        //"inputString+(char)key" Will fit into an Integer!
        inputString += (char)key;
    }
    else
    {
        //"inputString+(char)key" Will NOT fit into an Integer!
    }

Update 2: Looking at your edit, you're quite close. What's happening is when you add the char, it is getting added to end of the String, then parseInt is preformed on it. So adding the string "999999999" to the char (let's say it has a value of 1), will equal 9999999991 (or 9,999,999,991 when it's converted to a number) not 1,000,000,000. The number is then larger then an Integer by the time parseInt() is preformed on it.

Also, casting a int to a char will print out the ASCII character corresponding with the int's number, see this question for more on that.

To get the output you're looking for, try casting your inputString and key before adding them together. Example: (With inputString = 50 and key = 50)

Integer.parseInt(inputString) + (int)key    // = 100

Instead of:

Integer.parseInt(inputString+(char)key)      // Would equal 5050, but because 50 is the ASCCI character for 2, it will be 502.

Note that this will still throw an exception if you try to parse a number larger then 2147483647, so please consider enclosing it with a try/catch block.

Hope this helps you understand what's happening.

Community
  • 1
  • 1
Gulllie
  • 523
  • 6
  • 21
  • Thanks for the answer. To be clear, **my program does not crash** - it just sends an exception to the console. And because I add to the string one character at a time, the exception occurred when I got one character short of the number required to describe (2^31)-1. Before asking this question I was just limiting user input to below one billion but I thought it might be possible to do better. – Reason Nov 13 '16 at 04:27
  • Thanks for the update, but I think checking using `Long` kind of defeats the purpose. I'll just stick to testing it like this `if(Integer.parseInt(inputString+(char)key) < 999999999)` as this doesn't throw any exception. As well, I have already done checks to ensure that inputString is a number. – Reason Nov 13 '16 at 04:38
  • Do you also have checks to ensure the number in _inputString_ will fit into an Integer? Because _parseInt_ will throw an exception if it can't. With the Long example, all it does is parse _inputString_ to a long (just for the check), _then_ checks to see if it's value will fit into an Integer, in a way that _won't_ throw an exception if it can't (unless your number is to large to fit inside a long). – Gulllie Nov 13 '16 at 04:50
  • I really appreciate your help, but **this isn't really what I'm asking about.** Doing a check to limit user input to (10^9)-1 is the best that seems possible without extraneously parsing to `long`. I was hoping to understand more on **why** that is. (To be clear, I am accepting user input one character at a time, and only if the input is a number). I think I understand almost all of why the limit is (10^9)-1 now. I'd like to accept an answer that writes this out so other users can benefit from my question. I would answer my own question but I'm too new to the site to have the privilege. – Reason Nov 13 '16 at 20:46
  • Thanks for posting the answer @Gullie. I'm not sure why it ends up being (10^8)-1 instead of (10^9)-1. Probably something to do with the order in which it's being tested. I suppose this is as close as I'm gonna get. Hopefully this thread gets taken off hold. Thanks again. – Reason Nov 14 '16 at 04:17
  • I already made the edit @Gullie. I'm pretty sure it's because "we're testing `inputString` *plus* the next inputted digit." I hope that's right. I feel really uncomfortable answering my own question. **Maybe if this question wasn't put on hold we could be more productive.** – Reason Nov 15 '16 at 02:37
  • Could be the reason. Don't be, answering your own question is encouraged. :) Also, I agree, I think it's probably time this was put off hold. – Gulllie Nov 15 '16 at 03:05
0

Should be Integer.MAX_VALUE
Tried this and working

System.out.println(Integer.parseInt(String.valueOf(Integer.MAX_VALUE)));

Exception in thread "AWT-EventQueue-0" java.lang.NumberFormatException: For input string: "9999999999"

your input is definitely 9,999,999,999 and the maximum of integer is only 2,147,483,647

If you just want to check whether input is correct or not you can use this

boolean tryParseInt(String value) {  
 try {  
     Integer.parseInt(value);  
     return true;  
  } catch (NumberFormatException e) {  
     return false;  
  }  
}

if(tryParseInt(inputString+(char)key)){
            //input comes from the standard keyboard
            inputString += (char)key;
        }
    }else if(e.getKeyLocation() == KeyEvent.KEY_LOCATION_NUMPAD){
        if(tryParseInt(inputString+(char)(48+key-96))){
            //input comes from the numberpad
            inputString += (char)(48+key-96);
        }
    }
Hendrik T
  • 191
  • 7
  • You can run `System.out.println()` just fine. The problems arise when I'm testing the value. – Reason Nov 13 '16 at 03:02
  • Well, from your example, the problem must be on the input, not on the Integer.parseInt – Hendrik T Nov 13 '16 at 03:14
  • What do you mean by that? Could you rephrase it for a noob like me? – Reason Nov 13 '16 at 03:46
  • From your exception, the value that you try to parse is 9999999999 and not 999999999, 9 billion vs 999 million, as you know Integer max value is only around 2 billion – Hendrik T Nov 13 '16 at 03:47
  • Correct. I am trying to test to see if the input is below the maximum value Java can store so that the user doesn't accidentally crash the program by typing in a number that is too large. So to debug I am typing 9's until an exception in thrown. – Reason Nov 13 '16 at 03:58
  • in that case you should just use try catch – Hendrik T Nov 13 '16 at 04:02
  • Thanks Hendrik. I've considered just using `try`/`catch` or limiting input to 999,999,999 or smaller, but I was hoping to find out **why** Java operates in this way. Unfortunately, I think a sufficient number of people have down-voted my question that it won't be answered now. – Reason Nov 13 '16 at 04:12
  • Java don't behave this way or that way, it behave normally and predictable. It is that your programming logic that is wrong! It's hard to explain to you, you see there are so many answers already, all of them are answering your question! – Hendrik T Nov 13 '16 at 15:12
  • try this logic.. if you still don't get it then I'll stop answering you 1. is 999,999,999 less than 9,999,999,999? answer is true then program continue. 2. You press another '9' and it become 9,999,999,999, but before you can compare whether it is less than 9,999,999,999, the program need to convert it to Integer first.. that is where it failed! – Hendrik T Nov 13 '16 at 15:12
  • While I appreciate your input, I think you misunderstood what I was interested in. I must have written my question poorly. Look in the comments under the question. The answer to my question is here: http://pastebin.com/bq3vYZe4 – Reason Nov 13 '16 at 21:39
  • One more thing I'd like to make clear: I know how to make the program run without running into an exception. Please try to understand that I'm interested in "what's under the hood" of the JVM. I'm interested in **the best way** to do this, not just avoiding exceptions. – Reason Nov 13 '16 at 22:54
  • There were a number of bits and pieces from some of the comments on this question, yes, but no one actually linked their explanations to the JVM; no one has said the *why* - that much I had to mostly find out myself. At least as far as I can tell. None of the 4 answers were what I was looking for. You may want to take another look at the Help Center @Hendrik T for expected etiquette of users. http://stackoverflow.com/help/be-nice and/or http://stackoverflow.com/help/behavior seem relevant. Thanks for your time – Reason Nov 15 '16 at 08:11
0

Try removing (char)key when parsing the string. Any value 0-9 added at the end will always overflow the max integer value unless the first digit is a 1. 999,999,999 + key = 9,999,999,99x > 2147483647. You could use a long and check if the value is greater than Integer.MAX_VALUE.

String number = inputString+(char)(48+key-96);
if (Long.parseLong(number) >= Integer.MAX_VALUE) {
    if(Integer.parseInt(inputString+(char)(48+key-96)) < 999999999){
        inputString += (char) key;
    }
}
Matthew Wright
  • 1,485
  • 1
  • 14
  • 38
  • 1
    Thanks for your reply. Unfortunately this immediately throws `java.lang.NumberFormatException` as soon as I start typing input into the program. – Reason Nov 13 '16 at 03:09
  • What is the text after the exception. `For input string: "this number"`? – Matthew Wright Nov 13 '16 at 03:10
  • Mathew, I've pasted the full error report here because it's too long to fit into a comment: http://pastebin.com/kvifKPHf – Reason Nov 13 '16 at 03:13
  • I might be mistaken, but it looks like you passed in an empty string, and that's why it threw the exception. – Gulllie Nov 13 '16 at 03:28
  • Gullie, the program I'm running needs to be able to test input in real-time. I don't get an exception until I press a key, but yes; the report cites the input string as being empty. – Reason Nov 13 '16 at 03:42
0

You are parsing the string to test if the integer value is to large for integer to fit. If the value is to large for integer, then the parsing throws an error, because the result cannot be stored in an integer.

You should compare the 2 numbers lexographically as strings if the string is 10 digits long.

YourNumberAsString.compare(new String(Integer.MaxValue));

The result will tell you which number is bigger.

the value 0 if the argument string is equal to this string; a value less than 0 if this string is lexicographically less than the string argument; and a value greater than 0 if this string is lexicographically greater than the string argument.

http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#compareTo(java.lang.String)

HopefullyHelpful
  • 1,652
  • 3
  • 21
  • 37
  • Thanks so much for your answer. When I try doing things this way I still get a `NumberFormatException` though. I might just not understand lexicographical comparison well enough. I read the doc but I will reread and study this approach and accept this as an answer if it works. Thanks. – Reason Nov 13 '16 at 03:35
  • I've tried various methods but it seems that testing `inputString.compareTo("500")` for example returns unreliable values (I can type any number into the numberpad, and some values won't be permitted while others go completely unchecked. Can't type past 400 but can type in as many 9's as I like). Maybe it's testing the `String` and not the actual integral value? – Reason Nov 13 '16 at 03:53
  • More on that: I think I had the operator switched around the wrong way or something, but I think all the kinks have been worked out and it seems that using if(inputString.compareTo("500"+(char)key) <= 0) seems to only test superficially. It will allow any number starting with a value 1-4 through but not any value starting with 5-9. I cannot type "79" for example, but I **can** type "4323". – Reason Nov 13 '16 at 04:11
  • you need to check if both have the same length. only if both have the same length, then the lexographical comparison will yield correct results. – HopefullyHelpful Nov 13 '16 at 14:48
  • This was an interesting avenue to explore, HopefullyHelpful, thanks. To answer my question, however, I need to know why the biggest number I can test is (10^9)-1. See my comment under the question. I'm sorry I didn't realize this was off-topic earlier. – Reason Nov 13 '16 at 22:26