views:

155

answers:

4

I am getting a string from the user and then doing some checking to make sure it is valid, here is the code I have been using;

char digit= userInput.charAt(0) - '0';

This had been working fine until I did some work on another method, I went to compile and have been receiving a 'possible loss of precision' error since then.

What am I doing wrong?

A: 

Java may be converting userInput.charAt(0) and '0' to a different datatype before doing the subtraction, then converting back afterwards.

Try explicitly casting the result to char before storing it into digit:

char digit = (char)(userInput.charAt(0) - '0');
Benjamin Manns
This solved the problem, but now digit is not assigned a value at all...
Troy
@Troy: `digit` has to be assigned a value, it is a primitive type. Is the value binary 0? That would make sense if the charAt(0) was a '0'.
Kevin Brock
+6  A: 

For one thing you should be using the Character methods for doing this rather than a home grown solution, namely Character.isDigit() for checking validity and Character.digit() for getting a value:

char c = ...
if (Character.isDigit(c)) {
  // it's a digit
}
int value = Character.digit(c, 10);

Why you're getting this warning is explained by 5.6.2 Binary Numeric Promotion from the Java Language Specification:

When an operator applies binary numeric promotion to a pair of operands, each of which must denote a value of a numeric type, the following rules apply, in order, using widening conversion (§5.1.2) to convert operands as necessary:

  • If either operand is of type double, the other is converted to double.
  • Otherwise, if either operand is of type float, the other is converted to float.
  • Otherwise, if either operand is of type long, the other is converted to long.
  • Otherwise, both operands are converted to type int.

So what's happening is that when you do the subtraction both arguments are being promoted to ints. The result is an int. When you try and assign that int to a char there is a possible loss of precision (32 bit signed to 16 bit unsigned).

An alternative validation technique is simply to use a regular expression:

if (s.matches("\\d\\d-\\d\\d")) {
  // it's ##-##
}

or, if you need to grab the groups:

Pattern p = Pattern.compile("(\\d\\d)-(\\d\\d)");
Matcher m = p.matcher(s);
if (m.matches()) {
  System.out.println(m.group(1)); // first group
  System.out.println(m.group(1)); // second group
}
cletus
The problem is that I am checking to make sure the user enters a string in the format digitdigit-digitdigit, if it doesn't match this, or the numbers are outside of the range I am checking then I want to return an error.
Troy
@Troy why not use a regex of say `\d\d-\d\d` and testing the user input for that? If not, using `Character.isDigit()` can do the verification you want.
cletus
+1: Way to show me up.
Benjamin Manns
A: 

This has to do with how Java implicitly casts operands when used with arithmetic operators.

Both userInput.charAt(0) and '0' are of type char but they are implicitly converted to integers for the operation (subtraction) and hence when the integer result is assigned to a char, Java will given an error.

Peter
A: 

You really should use cletus' answer and I gave him +1. However, if you really want to use that subtraction in your code you should not store the result in a char at all, since the result can be negative (if the user enters " " (space) for instance).

int digit = userInput.charAt(0) - '0';
if (digit < 0 || digit > 9)
    throw new IllegalArgumentException("Bad input at 0, must be between 0 and 9.");

Of course, this should not have a hard coded index either unless you really just want to check the first position of that string.

Kevin Brock