constant expression require in java switch case (field is final and initialized) - java

public static final Integer SAMPLE = 100;
public static void doSomething(int errorCode) {
switch (errorCode) {
case SAMPLE:
// ...
break;
}
}
I got constant expression required. if i change SAMPLE to int it will get fix. why ?

The relevant parts of the language spec are in JLS Sec 14.11:
Every case label has a case constant, which is either a constant expression or the name of an enum constant.
This explains why you can't use an Integer value: it's not a constant expression, since it is evaluated at runtime.
The fix is to change the case label to have a constant expression. To know what types are allowed, read on in the same section of the spec:
Every case constant associated with the switch statement must be assignment compatible with the type of the switch statement's Expression (§5.2).
and
The type of the Expression must be char, byte, short, int, Character, Byte, Short, Integer, String, or an enum type (§8.9), or a compile-time error occurs.
Since you can't have a constant wrapped primitive type (Character, Byte, Short or Integer: they're all evaluated at runtime), this means that case labels can only be:
char
byte
short
int
String
An enum constant
The easiest option is to change your declaration of SAMPLE to:
public static final int SAMPLE = 100;
Note that 100 is in the guaranteed-cached range of Integer.valueOf, so there is no cost of declaring the value as a primitive: where you need a boxed value, a value is used from the cache.

Switch can only work with some primitives (char, byte, short, int), enum values and Strings.
change it to;
public static final int SAMPLE = 100;

Actually the switch statement can work with Integer.
Source: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html
The case is only working with constant values, e.g. primitives and compile-time String.
Your SAMPLE field that you pass to the case statement should be of primitive type.

Related

Null, primitive data value and wrapper class in method call [duplicate]

This question already has answers here:
Why is the default type of Java integer literals int instead of long? [closed]
(7 answers)
Closed 7 years ago.
I have following code snippet
public class Sample {
public static void main(String[] args) {
test(1);//fine & output - int
test(1L);//fine & output - long
//test(null); fine & output - Integer
test(12233333333);//error
}
static void test(int a){
System.out.println("int");
}
static void test(Integer a){
System.out.println("Integer");
}
static void test(long a){
System.out.println("long");
}
static void test(Long a){
System.out.println("Long");
}
static void test(List<Integer> a){
System.out.println("List");
}
}
My question is,
Why number value always refer int(primitive type) but null refer the most specific method among the overloads?
Why we need to say implicitly 1L why it not taking long value if u give big number(1233333333333)?
Can u some one explain those?
Why number value always refer int(primitive type) but null refer the
most specific method among the overloads?
Because by default compiler refers to the 32-bit integer operation for number without suffix l OR L (for long).
Why we need to say implicitly 1L why it not taking long value if u
give big number(1233333333333)? Can u some one explain those?
As I said above it by default refers to the integer operation and for such a big number it is out of the range of the Integer as this number will be considered as integer without suffix l or L so it will refer to the method which takes int as parameter but error comes up that value is out of range.
Let's see what JLS says..
JLS 4.2
If an integer operator other than a shift operator has at least one
operand of type long, then the operation is carried out using 64-bit
precision, and the result of the numerical operator is of type long.
If the other operand is not long, it is first widened (§5.1.5) to type
long by numeric promotion (§5.6).
Otherwise, the operation is carried out using 32-bit precision, and
the result of the numerical operator is of type int. If either operand
is not an int, it is first widened to type int by numeric promotion.
1233333333333 is an int literal so you could use that but you would have to cast it to long in which case the compiler will do the conversion. It does not work because it is too large to be an int.
The reason the compiler cannot just assume it is long is because ithey would be inconsistent with 123 being an int.

primitive == Wrapper converts to primitive == primitive or Wrapper == Wrapper?

I suppose that conversions described in jls are sorted according the priority.
first has greate priority.
jls
Thus I solved that Boxing has greater priority than Unboxing. I decided to check this assumption.
research following code:
public class BoxingUnboxingPriority {
public static void main(String [] args){
int sn = 1000;
Integer isn1= new Integer(sn);
System.out.println(sn == isn1 );
}
}
out:
true
What is boxing? is just new Integer(primitiveInt)
I changed the code a bit
int sn = 1000;
Integer isn1= new Integer(sn);
Integer isn2= new Integer(sn);
System.out.println(isn1 == isn2 );
out:
false
Thus I made mistake.
Please clarify me this issue.
The relevant section:
15.21.1. Numerical Equality Operators == and !=
If the operands of an equality operator are both of numeric type, or one is of numeric type and the other is convertible (§5.1.8) to numeric type, binary numeric promotion is performed on the operands (§5.6.2).
So:
Integer o = 1;
int i = 1;
boolean b = o == i;
...is equivalent to:
boolean b = o.intValue() == i;
Where both are of type Integer neither is a primitive numeric type - they are both object references.
When you use primitive with a Wrapper object, that wrapper object will be unboxed and then the operation will be applied.
In your first case, when you comparing sn with isn1, isn1 will be unboxed and the value will be compared. So you got true.
In second case, isn1, isn2 are two different object, so == operator will give false
I suppose that conversions described in jls are sorted according the priority.
That is incorrect. The JLS does not talk about "priorities" for conversions. It is not a recognized concept.
In fact, the conversions that can be applied are documented on a case by case basis for each operator, and so on. Thus JLS 15.21.1 says that == or != for numeric types results in "binary numeric promotion" of both operands. And JLS 5.6.2 says that binary numeric promotion consists of "unboxing conversion" (5.1.8) followed by "widening primitive conversion" (5.1.2) and finally "value set conversion" (5.1.3).
By contrast, JLS 15.21.3 says that when two references are compared using == or !=, no promotions or conversions take place.
(In fact, a common Java beginners mistake is to use == to compare two Integer objects rather than the equals(Object) method. And probably that is what "the question" you are looking at is trying to test your understanding of ...)
int sn=1000;
Integer isn1=new Integer(sn);
System.out.println(sn == isn1 );
will be converted to
System.out.println(sn == isn1.intValue());
while comparing primitive with wrapper the wrapper object first will be unboxed and then comparison.
wrapper object intValue() returns int so due to primitive comparison result true.
Integer isn1= new Integer(sn);
Integer isn2= new Integer(sn);
System.out.println(isn1 == isn2 );
// comparing two different object so false.

Why can't an enum value be fully qualified in a switch statement?

(note: edited question; the prior intent was not clear)
Consider this code:
public final class Foo
{
private enum X
{
VALUE1, VALUE2
}
public static void main(final String... args)
{
final X x = X.VALUE1;
switch (x) {
case VALUE1:
System.out.println(1);
break;
case VALUE2:
System.out.println(2);
}
}
}
This code works fine.
However, if I replace:
case VALUE1: // or VALUE2
with:
case X.VALUE1: // or X.VALUE2
then the compiler complains:
java: /path/to/Foo.java:whatever: an enum switch case label must be the unqualified name of an enumeration constant
SO suggests an answer with this quote from the JLS:
(One reason for requiring inlining of constants is that switch statements require constants on each case, and no two such constant values may be the same. The compiler checks for duplicate constant values in a switch statement at compile time; the class file format does not do symbolic linkage of case values.)
But this does not satisfy me. As far as I am concerned, VALUE1 and X.VALUE1 are exactly the same. The quoted text does not explain it at all for me.
Where in the JLS is it defined that enum values in switch statements have to be written this way?
SwitchLabel expects an EnumConstantName, which is defined as the enum constant identifier, which is unqualified:
EnumConstant:
Annotationsopt Identifier Argumentsopt ClassBodyopt

Constant expressions from an Enum

Is there any way of converting an enum into a constant expression?
I want my switch operator to choose among the values of an enum, but I got a compile error "case expressions must be constant expressions", so I tried to declare it in a variable:
final int REG = MyEnum.REG.getIndex().intValue();
switch (service.getIndex()) {
case REG:
But I still get the same error. According to Oracle's documentation http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28
A compile-time constant expression is an expression denoting a value
of primitive type or a String that does not complete abruptly and is
composed using only the following:
•Literals of primitive type and literals of type String
So it isn't working because I'm not using a literal. I think I will have to declare it as:
final int REG = 8;
But it'd be much better to link it to the enum. Is there any way of doing this?
EDIT
Turns out I don't need to use any final variable. It is just as simple as:
switch (service) {
case REG:
It didn't occur to me till I saw Andrea's comment. Thanks for your answers.
If possible, modify your getIndex() method so that it returns an enum instead of an integer. If this is not possible, you need to map the index to an enum element:
Given the following enum:
public enum Index {
ONE,
TWO,
THREE
}
you can map your index to an enum element by using
Index.values()[index]
Given your method Integer getIndex(), you can then do something like
switch(Index.values()[getIndex()])
case ONE : ...
break;
case TWO : ...
break;
case THREE : ...
break;
}
Note that this might throw an ArrayIndexOutOfBoundsException if you try to access an index within the enum which is larger than the number of enum elements (e.g. in the sample above, if getIndex() returns a value > 2).
I would encapsulate the expression Index.values()[getIndex()] into an enum method like valueOf(int index), similar to the default valueOf(String s). You can then also handle the valid array index check there (and for example return a special enum value if the index is out of range). Similarly, you can then also convert discrete values which have special meanings:
public enum Index {
ZERO,
ONE,
TWO,
THREE,
REG,
INVALID;
public static Index valueOf(int index) {
if (index == 8) {
return REG;
}
if (index >= values().length) {
return INVALID;
}
return values()[index];
}
}
This is an example only - in any case, it generally depends on the range of values you get from your getIndex() method, and how you want to map them to the enum elements.
You can then use it like
switch(Index.valueOf(service.getIndex())) {
case ZERO : ... break;
...
case REG : ... break;
...
}
See also Cast Int to enum in Java for some additional information (especially the hint that values() is an expensive operation since it needs to return a copy of the array each time it is called).
If you want specific numeral values assigned to enum constacts go like this
enum MyReg {
REG(8), OTHER(13);
public final int value;
MyReg(int value) {
this.value=value;
}
}
You then use it like this:
class Test {
public static void main(String[] args) {
MyReg reg = MyReg.REG;
switch (reg) {
case OTHER:
System.out.println(reg.value);
break;
case REG:
System.out.println(reg.value);
break;
}
}
}

Are arrays being transformed when using an enhanced for loop?

Does Java 5 or higher apply some of form of "boxing" to arrays? This question came to mind as the following code goes through an array as if it's an Iterable.
for( String : args ){
// Do stuff
}
Arrays are not primitives. Primitives are things that are not objects. Only boolean, char, byte, short, int, long, float, and double are primitives. Arraysare objects with special syntax. If you can call toString() on type in Java < 5 it is not primitive.
All autoboxing does is convert primitives to/from objects that expect objects such as ArrayList. It allows code like:
List<Integer> l = new ArrayList<Integer>();
l.add( 7 );
int i = l.get(0);
To be short hand for:
List<Integer> l = new ArrayList<Integer>();
Integer ii = Integer.valueOf( 7 )
l.add( ii );
int i = l.get(0).getIntValue();
This is all autoboxing does. Since String is already an object (and is not equivalent to char[] unlike in C) there is nothing to box/unbox String to.
Edit: added boolean as mentioned
Since you seem to be wondering about enhanced for loops in particular, the answer is that they are special-cased, not unboxed. From §14.14.2:
The enhanced for statement has the form:
EnhancedForStatement:
for ( VariableModifiersopt Type Identifier: Expression) Statement
The Expression must either have type Iterable or else it must be of an array type (§10.1), or a compile-time error occurs.
In fact, if the expression is an array, it is translated into the equivalent indexed for loop rather than actually using an iterator. The precise expansions are covered in the same section of the language spec.
No, arrays are always reference types. There's no need for boxing or unboxing, unless it's on the access for each element. For example:
int[] x = new int[10]; // The value of x is a reference
int y = x[0]; // No boxing
Integer z = x[1]; // Boxing conversion from x[1] (which is an int) to Integer
Also note that although the enhanced for loop is available for both arrays and iterables, it's compiled differently for each.
See section 14.14.2 of the JLS for the two different translations of the enhanced for loop.
No.
Unlike primitives, arrays (and strings) are Objects.

Categories

Resources