0

Why can't i do this?

public class test123 {
    public static void main (String [] args) {
        char c = 34;
        char a = c + 10;

    }
}

new to java, so sorry if this question is actually stupid.

fralorange
  • 31
  • 3
  • What is the result that you expect? – h0r53 Sep 21 '21 at 16:37
  • @Unmitigated even so, `char a = c + c;` wouldn't work. – Andy Turner Sep 21 '21 at 16:37
  • The `+` operator is actually a function that accepts two arguments (one on the left side and the other on the right side). In this case, that function does not have a definition for `char operator+(char, int)` – h0r53 Sep 21 '21 at 16:38
  • 2
    You're experiencing [Binary Numeric Promotion](https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.6.2), i.e. your variable `c` is promoted to an `int` because `10` is an `int`-literal. And the result from an `int` addition is still an `int`, so you'd have to cast the result back to a `char`: `(char) (c + 10)` – Lino Sep 21 '21 at 16:39
  • `int` is the narrowest type for arithmetic. Narrower values are widened to `int`, and the result is `int`. Try `char a = (char)(c + 10);` – Bohemian Sep 21 '21 at 16:40
  • @Andy I cover that in my answer. – Andy Turner Sep 21 '21 at 16:44
  • The best solution is to stop using the `char` type in Java. The `char` type is legacy, and is essentially broken. As a 16-bit value, it not capable of representing most Unicode characters. Instead, use Unicode [code point](https://en.wikipedia.org/wiki/Code_point) integer numbers. Use `int` to hold your code point, add 10, verify the new number is valid ([`Character.isValidCodePoint`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Character.html#isValidCodePoint(int))), then generate a single-character `String` holding that character: `Character.toString`. – Basil Bourque Sep 21 '21 at 17:06

3 Answers3

7

When you add numbers, they undergo binary numeric promotion. That is, the operands are widened to allow them to be added.

When you add a char to an int, the char is widened to an int, and the result is an int.

As such, you would have to cast the int back to a char:

char a = (char) (c + 10);

However, even when adding a char to another char, both are widened to int, and the result is again an int, and so cannot be assigned to a char variable. The rules are basically:

  • If either operand is a double, widen both to double
  • Else, if either operand is a float, widen both to float
  • Else, if either operand is a long, widen both to long
  • Else, widen both to int

So, even if you were adding a byte to a byte, both are widened to int, added, and the result is an int.


The exception to this is if you made c final:

final char c = 34;

In that case, c has a compile-time constant value, so c + 10 is a compile-time constant expression. Because it's a compile-time constant expression, the compiler knows its value, and knows that it fits into the range of char; so it would be allowed:

final char c = 34;
char a = c + 10;
Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • 1
    Why is it that you are allowed to assign an `int` to a `char` such as `char a = 10`, but you are unable to assign the `int` result of `operator+` to a `char`? – h0r53 Sep 21 '21 at 16:42
  • 2
    @h0r53 `10` is a compile-time constant expression, whose value can be determined by the compiler to fit in the range of `char`. I have demonstrated that you can assign the result of addition to a `char`, provided it has a compile-time constant value. – Andy Turner Sep 21 '21 at 16:43
  • This is misleading. It says that `c`, and the result, is widened to `int` because one of the operands is `10`, and suggests that coding `char a = c + c;` would work... but it doesn't. OP encounters the error because *all* types are widened to at least `int` when performing arithmetic. – Bohemian Sep 21 '21 at 16:46
  • 1
    " and suggests that coding char a = c + c; would work." where do I suggest that? – Andy Turner Sep 21 '21 at 16:46
  • I would like to add the JLS link: https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.6.2, but you keep editing :) – Lino Sep 21 '21 at 16:48
  • @Andy "the compiler knows its value, and knows that it fits into the range of char" the compiler knows that the value of `34 + 100000` is `100034`, which doesn't fit into the range of char, so it doesn't allow it. – Andy Turner Sep 21 '21 at 16:49
  • 1
    You state that `c` is widened to `int` because `10` is an `int`, which is a false statement. `c` is widened to `int` because **all** arithmetic is done using `int`. If you added a `byte` to a `char`, the `byte` would not be widened to `char`; both would be widened to `int`. – Bohemian Sep 21 '21 at 16:50
  • @Bohemian I absolutely do not say that. I say "Else, widen both to int". – Andy Turner Sep 21 '21 at 16:51
  • Rather than saying *When you add a `char` to an `int`, the `char` is widened to an `int`, and the result is an `int`.* it is more correct to say *When you add a `char` to **anything**, the `char` is widened to an `int` and the result is an `int` (except for legal compile time constants, or to `long` if the other operand is `long` etc)* – Bohemian Sep 21 '21 at 17:01
  • @Bohemian "When you add a char to anything" except when you add a char to a long, or a char to a float, or a char to a double. In those cases, the char is widened to a long, float or double respectively. Says it [here](https://docs.oracle.com/javase/specs/jls/se14/html/jls-5.html#jls-5.6): "If any expression is of type double, then the promoted type is double, and other expressions that are not of type double undergo widening primitive conversion to double." etc – Andy Turner Sep 21 '21 at 17:02
  • I was simplifying. Nevertheless, the operand `10` being `int` is not the cause of `c` being widened. – Bohemian Sep 21 '21 at 17:05
0

As per the JLS, int is the narrowest type for arithmetic. Narrower values are widened to int, and the result is int.

You would get the same error even if you coded:

char a = c + c; // error
Bohemian
  • 412,405
  • 93
  • 575
  • 722
0

The Java char is a primitive data type. It is used to declare the character-type like char char1='a'; But you can add an int to a char, but the result is an int - you'd have to cast back to char

char a = 'a';
char b = (char)(a+4);
System.out.println(b);// print "e"