Nesting Five Conditional Operators - java

Is it possible to nest more than 5 'Conditional Operators' in Java. I ask because it seems that I cause a compiler exception when I try to compile this code:
public Object getValue() {
return
number != null ? number :
string != null ? string :
bool != null ? bool :
date != null ? date :
list != null ? list :
null;
}
I have narrowed it down to this code because if I comment out the last line it seems to compile fine.
public Object getValue() {
return
number != null ? number :
string != null ? string :
bool != null ? bool :
date != null ? date :
// list != null ? list :
null;
}
Does anybody else know if this is a limitation of the java compiler or am I jumping to false conclusions, it would be great if someone else could try to reproduce this. If anybody is interested I have reproduced and posted the Stack Trace from the compiler here https://gist.github.com/919284.
Note that it is very likely a bug in the compiler not my code, as the output said "Please File a Bug at Java Developer Connect site" (or something similar). I am asking here because I am not sure what that bug report would contain.
EDIT:
Chris L has reproduced this, see his answer

I reproduced your error (using Sun JDK 1.6.0_24 on Mac). I simplified your class a little bit to:
import java.util.ArrayList;
import java.util.Date;
public class Test3 {
private Number number;
private String string;
private Boolean bool; // Replace Boolean with Object, and it compiles!
private Date date;
private ArrayList<String> list; // Replace ArrayList with List, and it
// compiles!
public Object getValue() {
return number != null ? number :
string != null ? string :
bool != null ? bool :
date != null ? date :
list != null ? list :
null;
}
}
My stack trace is basically the same as yours. (It has nothing to do with GWT, by the way.)
An exception has occurred in the compiler (1.6.0_24). Please file a bug at the Java Developer Connection (http://java.sun.com/webapps/bugreport) after checking the Bug Parade for duplicates. Include your program and the following diagnostic in your report. Thank you.
java.lang.AssertionError
at com.sun.tools.javac.jvm.Code$State.forceStackTop(Code.java:1688)
at com.sun.tools.javac.jvm.Gen.visitConditional(Gen.java:1679)
at com.sun.tools.javac.tree.JCTree$JCConditional.accept(JCTree.java:1021)
at com.sun.tools.javac.jvm.Gen.genExpr(Gen.java:818)
at com.sun.tools.javac.jvm.Gen.visitConditional(Gen.java:1678)
at com.sun.tools.javac.tree.JCTree$JCConditional.accept(JCTree.java:1021)
at com.sun.tools.javac.jvm.Gen.genExpr(Gen.java:818)
at com.sun.tools.javac.jvm.Gen.visitConditional(Gen.java:1678)
at com.sun.tools.javac.tree.JCTree$JCConditional.accept(JCTree.java:1021)
at com.sun.tools.javac.jvm.Gen.genExpr(Gen.java:818)
at com.sun.tools.javac.jvm.Gen.visitReturn(Gen.java:1626)
at com.sun.tools.javac.tree.JCTree$JCReturn.accept(JCTree.java:1138)
at com.sun.tools.javac.jvm.Gen.genDef(Gen.java:665)
at com.sun.tools.javac.jvm.Gen.genStat(Gen.java:700)
at com.sun.tools.javac.jvm.Gen.genStat(Gen.java:686)
at com.sun.tools.javac.jvm.Gen.genStats(Gen.java:737)
at com.sun.tools.javac.jvm.Gen.visitBlock(Gen.java:1013)
at com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:739)
at com.sun.tools.javac.jvm.Gen.genDef(Gen.java:665)
at com.sun.tools.javac.jvm.Gen.genStat(Gen.java:700)
at com.sun.tools.javac.jvm.Gen.genMethod(Gen.java:893)
at com.sun.tools.javac.jvm.Gen.visitMethodDef(Gen.java:866)
at com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:639)
at com.sun.tools.javac.jvm.Gen.genDef(Gen.java:665)
at com.sun.tools.javac.jvm.Gen.genClass(Gen.java:2198)
at com.sun.tools.javac.main.JavaCompiler.genCode(JavaCompiler.java:617)
at com.sun.tools.javac.main.JavaCompiler.generate(JavaCompiler.java:1289)
at com.sun.tools.javac.main.JavaCompiler.generate(JavaCompiler.java:1259)
at com.sun.tools.javac.main.JavaCompiler.compile2(JavaCompiler.java:765)
at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:730)
at com.sun.tools.javac.main.Main.compile(Main.java:353)
at com.sun.tools.javac.main.Main.compile(Main.java:279)
at com.sun.tools.javac.main.Main.compile(Main.java:270)
at com.sun.tools.javac.Main.compile(Main.java:69)
at com.sun.tools.javac.Main.main(Main.java:54)

I can only confirm that this compiles without error for me in both eclipse 3.5 and javac 1.6.0_u24:
public class Test {
Object number=null, string=null, bool=null, date=null, list=null;
public Object getValue() {
return
number != null ? number :
string != null ? string :
bool != null ? bool :
date != null ? date :
list != null ? list :
null;
}
}

This compiles fine on ideone:
public static void main (String[] args) throws java.lang.Exception
{
Object number = null;
Object string = null;
Object list = null;
Object bool = null;
Object date = null;
Object o =
number != null ? number :
string != null ? string :
bool != null ? bool :
date != null ? date :
list != null ? list :
null;
}
Double check that list is declared in a way that it is accessible inside the method.
May be a bug in your java compiler. I suggest you update your java to the latest and greatest (if there is one) and reproduce. You can install as many different versions of Java as you like.

I don't think there is a limitation while it is syntactically correct. I would guess the java compiler just will expand its parse tree like for a deep if/else if - nesting.

There is no limit as low as this. A method must compile to less than 64KB of byte code.
I compiled your example fine. Is there any reason you don't have just one field?
EDIT: Added setters to check valid types.
public class Holder implements Serializable {
Serializable value;
public void setValue(Number value) {
this.value = value;
}
public void setValue(String value) {
this.value = value;
}
public void setValue(Boolean value) {
this.value = value;
}
public void setValue(Date value) {
this.value = value;
}
public <L extends List & Serializable> void setValue(L value) {
this.value = value;
}
public Serializable getValue() {
return value;
}
}

I know this is an old post, but my recent experiance might shed some light on the subject for those of you who are interested. It's something to be aware of.
Basically, I "broke" some existing code by implementing Comparable in one of my other classes. Here's a stripped down version that generates the same "An exception has occurred in the compiler..."
If there are fewer than 5 expressions in the nested conditional, or if the USDollars class does not implement Comparable this code compiles.
public class TestHit
{
protected final String fSymbol;
protected final long fTime;
protected final USDollars fBasePrice;
public TestHit(String aSymbol, long aTime, int aBasePrice)
{
fSymbol = aSymbol;
fTime = aTime;
fBasePrice = new USDollars(aBasePrice);
}
public Object field(int aIndex)
{
return (aIndex == 0)? fSymbol
: (aIndex == 1)? fTime
: (aIndex == 2)? fBasePrice
: (aIndex == 3)? new Integer(4) // comment out this line and it compiles
: "?";
}
}
final class USDollars
implements Comparable<USDollars> // comment out this line and it compiles
{
private int cents;
public USDollars() { this(0); }
public USDollars(int cents) { this.cents = cents; }
public USDollars(int dollars, int cents) { this(cents + 100*dollars); }
public int cents() { return cents; }
// #Override
public int compareTo(USDollars other) { return this.cents - other.cents; }
}
By the way, a quick fix was to modify the code as follows (ugly but it works):
public Object field(int aIndex)
{
if (aIndex == 2)
return fBasePrice;
return (aIndex == 0)? fSymbol
: (aIndex == 1)? fTime
: (aIndex == 3)? new Integer(4) // comment out this line and it compiles
: "?";
}

Related

How to resolve Java.lang.numberformatexception: empty string

I have a utility function which convert parseDouble value to string.
public static BigDecimal setValue(Object o) {
BigDecimal value = new BigDecimal(0);
if(o!= Null){
value=BigDecimal.valueOf(Double.parseDouble(o.toString()));
}
return value;
}
I have tried with (o!=null && !isEmpty(o)) and (o!="" && o!=null) but it is still throwing same error.
Transaction amount which is processing this utility function contains empty value.
Firstly I don't understand why you are taking object type as an input, however to resolve your issue you can do something like this. But I would strongly advice you to change the method signature it is misleading.
public static BigDecimal setValue(Object o) {
var value = new BigDecimal(0);
if (o != null) {
if(o instanceof String) {
if (((String) o).trim().length()>0) {
value = new BigDecimal((String) o);
}
}
}
return value;
}
I would change the method signature to BigDecimal setValue(String s). Your null check and length check code should then work fine.
Also the method name is misleading. The method does not set anything. Something like convertToBigDecimal would be clearer.

CompareTo is transitive

I have a POJO looking like this:
public class Pojo implements Comparable<Pojo> {
private String type;
private String journalId;
private Date bookingDate;
private Long account;
private String description;
private BigDecimal debit;
private BigDecimal credit;
....
}
and I want to sort a list of these POJOs. Currently my compareTo method looks like this:
#Override
public int compareTo(EfdisJournal other) {
int i = this.type.compareTo(other.type);
if (i != 0)
return i;
if (this.bookingDate != null && other.bookingDate != null)
i = this.bookingDate.compareTo(other.bookingDate);
if (i != 0)
return i;
if (this.journalId != null && other.journalId != null)
i = this.journalId.compareTo(other.journalId);
if (i != 0)
return i;
return this.account.compareTo(other.account);
}
If I run a sort with this compareTo method, I get this java.lang.IllegalArgumentException: Comparison method violates its general contract error. I did google a bit and I think it happens because some of the fields are null on comparison. Yet I have no idea how to solve this or if I am right why that error appears.
The comparison should work like this: 1st compare by type, then compare by bookingDate, as 3rd compare by journalId and at last compare by account. All comparisons should be ascending.
type is never null
bookingDate may be null
journalId may be null
account is never null
EDIT:
Sadly I was not able to implement the method, so that the order is as needed. Yet, i solved the problem I had, because the stored procedure yielded 2 resultsets, of which the second was order as needed, so the only thing I had to do was to use the 2nd resultset instead of the first.
You need to deal with the case where one instance has a null bookingDate, and the other has a non-null bookingDate.
You should decide whether things with null bookingDate should be sorted before or after things with a non-null bookingDate, and write your compareTo appropriately. (And then journalId too.) Then you can get an order that sorts consistently.
For instance:
#Override
public int compareTo(EfdisJournal other) {
int i = this.type.compareTo(other.type);
if (i != 0) {
return i;
}
if ((this.bookingDate==null) ^ (other.bookingDate==null)) {
return (this.bookingDate==null ? -1 : 1);
}
if (this.bookingDate != null && other.bookingDate != null) {
i = this.bookingDate.compareTo(other.bookingDate);
}
if (i != 0) {
return i;
}
if ((this.journalId==null) ^ (other.journalId==null)) {
return (this.journalId==null ? -1 : 1);
}
if (this.journalId != null && other.journalId != null) {
i = this.journalId.compareTo(other.journalId);
}
if (i != 0) {
return i;
}
return this.account.compareTo(other.account);
}
You're ignoring situations where bookingDate and/or journalId is null with one and non-null with the other.

Java - getMethod null check

I have a class as below, before I set the data I need to check whether getValue() is present and it's value is empty.
public class Money {
{
private String value;
private String currency;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getCurrency() {
return currency;
public void setCurrency(String currency) {
this.currency = currency;
}
}
//JSON is like this
"money": {
"currency": "USD",
"value": ""
}
I want to check whether this getValue() is present or not like obj.getMoney().getValue() != null,
and then I need to check it's value is empty... obj.getMoney().getValue().equals("") but it fails on this condition obj.getMoney().getValue() != null as null.
If the following check fails
if (obj.getMoney().getValue() != null) { ... }
then it implies that the money object itself is null. In this case, you can slightly modify your if condition to check for this:
if (obj.getMoney() != null && obj.getMoney().getValue() != null) { ... }
You said that first you need to check whether value is null or not and then also check whether the value is empty or not,
You can do the following
if (obj.getMoney() != null && obj.getMoney().getValue() != null && !obj.getMoney().getValue().isEmpty()) {
// rest of the code here
}
obj.getMoney().getValue() will give you null pointer exception. You should check for null object before using . after it. Example code:
Below code looks huge but it's actually readable and it will be optimized by compiler.
if(obj != null){
Money money = obj.getMoney();
if(money != null) {
String value = money.getValue();
//Add you logic here...
}
}
I think you are getting null point exception. You are facing this exception because obj.getMoney() is already null. Since you are trying to get a null object's value, so you are getting this exception. Correct code will be
if ((obj.getMoney() != null) && (obj.getMoney().getValue().trim().length() > 0)) {
// Execute your code here
}
When instantiating your obj, gives a new. The form of validation is correct, the problem is in the obj that was not initialized. (I believe)

Testing an overriden equals method

I'm reading J. Bloch's effective Java and needed to brush up the equals/hashCode contracts and relationships.
I have the following JavaBeans class:
public class MyJavaBean{
private int id;
private Properties fItem; //Enumeration type
private String value;
private Rule rule; //Enumeration type
private int fId;
//GET, SET
#Override
public boolean equals(Object o){
if(!(o instanceof MyJavaBean))
return false;
MyJavaBeanv = (MyJavaBean) o;
return (fItem == null ? v.fItem == null : fItem.equals(v.fItem)) &&
(value == null ? v.value == null : value.equals(v.value)) &&
(rule == null ? v.rule == null : rule.equals(v.rule)) &&
fId == v.fId && id == v.id;
}
#Override
public int hashCode(){
int result = 17;
if(fItem != null)
result = 31 * result + fItem.hashCode();
if(value != null)
result = 31 * result + value.hashCode();
if(rule != null)
result = 31 * result + rule.hashCode();
result = 31 * result + fId;
result = 31 * result + id;
return result;
}
}
He also suggest we write unitTests to make sure the contracts are actually satisfied. Here is what he said(italic-bold emphasize mine):
When you are finished writing your equals method, ask yourself three
questions: Is it symmetric? Is it transitive? Is it consistent? And
don’t just ask yourself; write unit tests to check that these
properties hold!
So, I can't imagine how to write unit test for that pretty straightforward case. Well, I'd write something like that:
public class MyTest{
//Each pair consists of the equals object
private Map<MyJavaBean, MyJavaBean> equalValueMap;
#Before
public void init(){
//initializing the map, using ThredLocalRandom
//to get ints and enums randomly
}
#Test
public void testReflexive(){
for(MyJavaBean fiv: equalValueMap.keySet()){
Assert.assertEquals(fiv.equals(fiv), true);
}
}
#Test
public void testSymmetric(){
for(MyJavaBean fiv: equalValueMap.keySet()){
Assert.assertEquals(equalValueMap.get(fiv).equals(fiv), true);
Assert.assertEquals(fiv.equals(equalValueMap.get(fiv)), true);
}
}
#Test
public void testHashCode(){
for(FilterItemValue fiv: equalFilterValueMap.keySet()){
Assert.assertEquals(equalFilterValueMap.get(fiv).hashCode(), fiv.hashCode());
}
}
}
But I think such tests just waste the build-time, because of their simplicity. Is it worthy to write tests for the methods for simple JavaBeans?
IMHO! You can safely skip the tests for equals() and hashCode() if they are generated by an IDE / some helping library you trust.
Although, if you're really doing some complex things and worry if these methods may not behave as desired in runtime, it might be worth spending time and writing a simple test.

Java Type Cast, Object Type and overloading Issue

Please have a look on following Class, I need to check if there is valid value in the variable. All works fine if there is a proper value in variable instead of null, When it comes null the behaviour is not what I expect (Although it might make sense if Integer a = null; when checked as a instanceof Integer,
Can some one guide me how to achieve correct result from following class?
package com.mazhar.hassan;
public class ValueChecker {
public static boolean empty(Integer value) {
System.out.println("Integer");
return (value != null && value.intValue() > 0);
}
public static boolean empty(Long value) {
System.out.println("Long");
return (value != null && value.longValue() > 0);
}
public static boolean empty(String value) {
System.out.println("String");
return (value != null && value.length() > 0);
}
public static boolean empty(Object value) {
System.out.println("Object");
return (value != null);
}
public static void checkAll(Object... args) {
for(Object o: args) {
if (o instanceof Integer) {
empty((Integer)o);
}
else if (o instanceof Long) {
empty((Long)o);
}
else if (o instanceof String) {
empty((String)o);
}
else {
empty(o);
}
}
}
public static void main (String[] args) {
Integer a = null;
Long b = null;
String x = null;
Object y = null;
if (a instanceof Integer) {
System.out.println("a is Integer");
} else {
System.out.println("a is not Integer");
}
System.out.println("/---------------------------------------------------/");
checkAll(a,b,x,y);
System.out.println("/---------------------------------------------------/");
empty(a);
empty(b);
empty(x);
empty(y);
}
}
Why I need exact type checking is, I thave to throw erros like "Not valid Integer", "No valid Long" etc.
The output of above class is as follows.
/-----------------------(Output 1)----------------------------/
a is not Integer
/-----------------------(Output 2)----------------------------/
Object
Object
Object
Object
/------------------------(Output 3)---------------------------/
Integer
Long
String
Object
Output 1: a is not integer (checked by instanceof) can not recognize it but when passed to a overloaded function goes to the right function (Output 3)
Output 2: How to achieve checkAll with multiple/dynamic param checkAll(varInt, varLong, varString, varObject)
The behaviour for Output 1 is caused by the fact that method overloads are bound at compile time. So the specific overload to pick is bound before the program even runs. instanceof, on the other hand, is a runtime check.
Thus, at runtime a instanceof Integer is effectively null instanceof Integer, which is obviously false.
But for each of those individual method calls, the proper method is called because the compiler bound the specific overload of the method at compile time, based on the reference type of the variable. Thus:
empty(a); // Compiled to a call to empty(Integer value)
empty(b); // Compiled to a call to empty(Long value)
empty(x); // Compiled to a call to empty(String value)
empty(y); // Compiled to a call to empty(Object value)
So regardless of the actual object that a, b, x, and y reference, you'll always get the right output on your console for the respective object.
Output 2: How to achieve checkAll with multiple/dynamic param checkAll(varInt, varLong, varString, varObject)
Well, if you're going to pass null, you can't really. null is null at runtime, and doesn't have any type information associated with it. The JVM can't tell that one null is a "String null" or an "Object null". It's just null. So you can't really implement the multiple check you want to for null inputs -- null instanceof ______ will always return false, so you'll always end up with your default case.
If you pass actual objects, though, that method should work properly.
problem:
Integer a = null;
Long b = null;
String x = null;
Object y = null;
You cant use instanceof on null values, it expect the objects to be instantiated thus giving you wrong result.
solution:
instantaite the object first before you check for instance.
The problem here is that when you check instanceof in your loop, you are checking null. null is not an instance of anything, it is the absence of an instance.
If you want to achieve something like this, you're going to have to change your API for checkAll(Object ...) to something that tells the function what types to expect:
public class ValueChecker {
public static boolean checkAll(Object[] args, Class<?>[] types) {
if (args == null || types == null || args.length != types.length)
throw new RuntimeException("programming error");
for (int i = 0; i < args.length; i++) {
if (types[i] == null)
throw new RuntimeException("programming error");
if (args[i] == null || !types[i].isAssignableFrom(args[i].getClass())) {
System.out.println("arg " + (i +1) + " is not " + types[i].getSimpleName());
return false;
}
}
return true;
}
public static void main(String[] args) {
Integer a = null;
Long b = null;
String x = null;
Object y = null;
checkAll(
new Object[] {a, b, x, y},
new Class<?>[] {Integer.class, Long.class, String.class, Object.class}
);
}
}

Categories