Java
Fone: 8h - 17PM

Dextra

Java Annoyances

By: 08/08/2016

Java is great. Don’t get me wrong, it really is. It’s so vastly widespread because it’s extremely powerful, fast, adaptable and reliable. But of course there are several problems, some inherent to the language itself, and some that happen to be small details that can be easily fixed.

This article is about this second kind of flaws, things that clearly should not be the way they are, however can be easily fixed. I’ve encountered many of them through my experience, and decided to compile this list with the most interesting ones. They are not exceedingly common, but when they occur, they can get you stuck for hours, so it’s definitely worth reading. If nothing else, they are all very interesting and reveal curious aspects of our beloved language.

1. Generic array creation

The most infamous and misunderstood compile message, error: generic array creation is already a commonplace Java-doesn’t-work argument. And like losing the end of the scotch tape, it doesn’t take anything extraordinary for it to happen; take this example:

public class Bag<T> {
    private T[] ts;

    public Bag(int size) {
        this.ts = new T[size];
    }
}

 

This code, as simple as it gets, just doesn’t compile, giving the aforementioned justification. The reason, as one can assume, is that you cannot instantiate a array of generic component type in Java. Period.
This is because Type Erasure, a backward-compatibility insuring mechanism that destroyed a substantial fraction of Java potential. Since the types are erased at compile time, the compiler is complaining that the runtime will not be capable of performing the necessary type checks to guarantee the desired result. That’s why it gives an error. To understand it better, let’s see some simpler array examples. First of all, let’s remind that Java arrays are covariant. This means that if Child extends Parent, then Child[] extends Parent[] as well:

Integer[] is = new Integer[5];
Number[] ns = is; // ok, because Integer[] is Number[]

 

This was done to allow better APIs; for example, a method that does a common operation to any array can receive a Object[] objs, and you would be able to call it with any array in your code.
However, there are some typing problems:

Object[] a = new String[2]; // ok, covariant
a[0] = Boolean.TRUE; // Boolean is Object, oops

 

Here, we create a array of Strings and then look at it as an array of Objects, witch it is. So the compiler allows the second line. However, this properly fails at runtime, giving a java.lang.ArrayStoreException, and making sure the rule we established upon instantiating a String[] array is respected. We therefore say that arrays in Java are reifiable, that is, they store they instantiation type at runtime.

So, in short, we can see arrays as their Parent‘s, but we can only store up to what we specified upon instantiation.

Back to our problem, if we instantiate a new T[] array, we are expecting to have this runtime check that all elements are indeed of type T, even if we later start observing this array as a Object[] array. However, due to type erasure, this just isn’t possible, because the type T is lost at runtime, and we are left with a new Object[] bytecode. All type-checking for generics must be done at compile time. That’s why the compiler would not let this happen, as it’d break the type system integrity.

So, how to fix it? Short answer, use a List. Longer answer, use a fucking List. Really, there is no way not to do that, whatsoever. But let’s dig into that a bit more. Why would a list work? Because Generics are not covariant, at least not the way arrays are. That means a List<Integer> is not a List<Number>. Generics solves the covariance problem with a much, much more elegant solution, that is wildcards. I could write a whole other article about Covariance and Contravariance with Wildcards, but for the purposes of this item, we would just do:

public class Bag<T> {
    private List<T> ts;

    public Bag(int size) {
        this.ts = new ArrayList<>(size);
    }
}

 

Actually, looking at it this way, this class Bag is useless, as it’s just a wrapper for List.

But okay, okay, what if you really need it to be an array? Maybe you are integrating with a API that’s not under your control, or maybe you want to know how the ArrayList class does it…

Well, there are two ways of solving this. In both, however, you need to make sure to do the runtime checker’s job to maintain refiability. The first one requires a reference to the type at hand:

@SuppressWarnings("unchecked")
public Bag(Class<T> clazz, int size) {
    this.ts = (T[]) Array.newInstance(clazz, size);
}

 

Note that I need to receive a Class token to be able to instantiate it at runtime with reflection. This is the safer way, but requires to change the API to receive this token. Also, you need to suppress the warning, to explicitly tell the compiler that’s indeed what you want to do, and that you guarantee safe in every usage of this array. If that is not an option, you need to do the work by yourself. That is, use a Object (or the erased type) array.

public class Bag<T> {
    private Object[] ts;

    public Bag(int size) {
        this.ts = new Object[size];
    }
}

 

Here we wanted a T array to get compile time checks, but we can’t have that, so we inform the compiler we abdicate by using a plain Object array. It will now be our job, as the implementer, to make sure everything stored is of type T (using a set(T t) method, for example), so that everything we get can be safely cast to T as well. When doing so, you will need to suppress a warning, to inform the compiler you are aware of what you are doing and there are no flaws. This is completely transparent to the user of the system, but one care must be taken: you must never never never return a reference to this array to outside of this class! Because then you’d loose control and not be sure anymore of what’s stored in there. That’s how ArrayList does it.

A variation, taking advantage of casting, is the following:

public class Bag<T> {
    private T[] ts;

    public Bag(int size) {
        this.ts = (T[]) new Object[size];
    }
}

 

This will also give a warning, warning: [unchecked] unchecked cast. Again, the same principle occurs: you must check yourself everything stored in ts is indeed of type T. The runtime will not do that for you. Once you are sure you are doing that, you can safely suppress the warning.

2. Generic Enums

So generic arrays have their problems, but at least they exist. Look at this simple excerpt:

public interface Convertible<T> {
    public T convert();
}

enum A<T> implements Convertible<T> {
    A1<String>() {
        @Override
        public String convert() {
            return "a1";
        }
    },
    A2<Integer>() {
        @Override
        public Integer convert() {
            return 2;
        }
    }
}

 

The intent of this snippet is clear as water, yet the compiler complains about the syntax. Indeed, this syntax is not predicted in any way in the JLS, and generic enums simply don’t exist in Java. Well, that’s a bummer.

But fear not, as not all is lost. There are a few workarounds that work just as well. The first solution is the simplest: get rid of the enun altogether. Many people nowadays are completely unaware of how things were before Java 1.5. Enums evolved from a very common pattern that was used without any problems for a long time before the syntax sugar was introduced. They were a list of static final instances of a Class that had no other ways of being created.

Of course there are inconceivable more advantages for using enums over that, but since they can’t be generic, one very simple elegant solution is to resort to the archaic way of doing things; take a look at this example:

final class A<T> implements Convertible<T> {
    public static final A1 = new A<String>() {
        @Override
        public String convert() {
            return "a1";
        }
    };
    public static final A2 = new A<Integer>() {
        @Override
        public Integer convert() {
            return 2;
        }
    };

    private A() {}
}

 

Note there are a bit of boilerplate additions, but nothing that disgraces the solution. In fact, when using, this is pretty much indistinguishable from a proper enum (except for a few perks, like switches). One could call A.A1, or receive a A object in a method, and wouldn’t notice a difference.

However, let’s say enums are, for some reason, very important to you. Well, create several, then! The following is a very elegant workaround to this problem:

final class A {
    private enum AString implements Convertible<String> {
        A1 {
            @Override
            public String convert() {
                return "a1";
            }
        }
    }
    private enum AInteger implements Convertible<Integer> {
        A2 {
            @Override
            public Integer convert() {
                return 2;
            }
        }
    }

    public static final Convertible<String> A1 = AString.A1;
    public static final Convertible<Integer> A2 = AInteger.A2;
}

 

Of course you would create only one enum class per generic type, and add all constants to the proper enums. Both of these solutions are very good, and it is up to your specific problem to choose either.

3. Static references in enums’ constructors

Let’s suppose you are making an enum that has to be identified with a unique numeric id. You decide to generate that on the constructor, so you don’t have to specify it for every single constant. Well, you might try something like this:

public enum A {
    A1, A2;

    private static int count = 0;

    private int id;

    private A() {
        this.id = count++;
    }
}

 

A very simple example, that will assign sequentially generated ids to your constants. Except it doesn’t compile. Why? javac will blatantly spit this out: error: illegal reference to static field from initializer. Well, apparently you can’t do that, then… You say ‘Okay’ to javac and move on to write the ids manually, after all, it’s just 250 more constants.

Well, not so fast. There are several very easy workarounds, but before using any of them let’s understand why this happens. javac is not crazy nor picky: it has a point. Let’s remember that enums constants declaration are nothing more than static final fields of a class, that are initialized before anything else. Well, if they are initialized before anything else, how can they access other equally defined static final fields? Those haven’t been initialized yet! Let’s see a simpler example to find out where the problem is:

public enum MyEnum {
    CONSTANT;
    private MyEnum e = CONSTANT;
}

 

This extremely simple snippet fails for the exact same reason. But why? Let’s see how the compiler sees this code, after it processes the syntax sugar into regular static final constants; let’s also move the field initializer to the constructor, because that’s when the compiler run this instruction:

public class MyEnum {
    private static final MyEnum CONSTANT = new MyEnum();

    private MyEnum e;

    private MyEnum() {
        this.e = CONSTANT;
    }
}

 

(I’m not saying, be noted, that the compiler actually does this conversion, ok? I’m just illustrating with a example that generates a very similar bytecode and it’s closer to the machine level)

Here, we can see the problem stands out more than a police siren in a deserted theater. How can we possibly access CONSTANT in the constructor, if we need to call the constructor to define it? Well, we can’t. Since enum constants are initialized before anything else, and they all called the enum’s constructor (even if a empty default one), you simply cannot make static references to the enums class there.

Now that we know the exact reason for this error, we already have a good hint on how to solve it (the emphasis in the last sentence might have given a clue as well). We just need to put the static field in a different class. Then, none of this problems will exist. Simplest solution?

public enum A {
    A1, A2;

    private static class Ids {
        static int count = 0;
    }

    private int id;

    private A() {
        this.id = Ids.count++;
    }
}

 

Simple as that. Of course you could make a more elaborated class, put that in another file, or anything your heart desires.

4. Cyclic dependency in enums’ constructors

Suppose this very simple example. We have two enums, A and B, and there is a 1:1 relation between them, so we decide to map that both ways; that is, A will hold a ref to B and vice-versa. We could implement that like this:

public enum A {
    A1(B.B1), A2(B.B2);

    B b;

    private A(B b) {
        this.b = b;
    }
}

public enum B {
    B1(A.A1), B2(A.A2);

    A a;

    private B(A a) {
        this.a = a;
    }
}

 

Seems fairly simple and straightforward, right? Now what do you think will be the output of this code, when run in a main method?

    System.out.println(A.A1.b + " " + B.B2.a);

 

One would very rationally arguee that it should print "B1 A2" right? Well, run it for yourself and you shall see it prints "B1 null". ‘What?’, you might ask. And that is the right question.

This is from article 17.5.2 from the JLS (Java Language Specification), emphasis mine:

A read of a final field of an object within the thread that constructs that object is ordered with respect to the initialization of that field within the constructor by the usual happens-before rules. If the read occurs after the field is set in the constructor, it sees the value the final field is assigned, **otherwise it sees the default value**.

What happens when you create a scenario in witch two final fields, statically initialized, one depend on the other? It seems impossible to do such a thing, but since Java 1.5 added enums, it is very much possible (and common) for people to create cyclic enum dependency in their constructors, that is, two enums that reference each other’s constants in their constructors.

As we can see in the spec, if there is a value assigned, fine, it is returned, but otherwise the default value (null), in this case, is returned. Let’s see what happens in a bit more depth.

  • the main class is loaded
  • main refers to the enum A, so A is loaded
  • static initialization of A happens, i.e. its enum constants will be initialized in the order they are declared
  • A1 initializer references B, so B is loaded
  • static initialization of B happens
  • B1 initializer references A1

This is where everything breaks. A is already loaded in the class loader, but A1 has not yet been initialized (we are in the middle of doing so!). So according to the spec the A1 ref returns null. Then everything flows as expected, A1.b is set properly (the first reference), but B1.a is left broken.

As you can see this is a gigantic problem because it even depends on the order of loading, because either the refs on A‘s side or on B‘s side can be left null. As there is no standard on the order the Class Loader decides to load classes (if the same file references both A and B), the same code might get different results on different machines!

Luckily this problem is as obscure and dangerous as it is easy to fix. In fact, there are a plethora of solutions that would circumvent this problem altogether.

One idea is to bind the references not in the constructor, but in a static block. That way there is time for the class loader to initialize everyone, calling now empty constructors, and then set all the refs properly:

public enum A {
    A1, A2;

    B b;

    static {
        A1.b = B.B1;
        A2.b = B.B2;
    }
}

public enum B {
    B1, B2;

    A a;

    static {
        B1.a = A.A1;
        B2.a = A.A2;
    }
}

 

This would even allow to bind them both ways simultaneously, with a method bind(A a, B b) that guarantees that 1:1 relationship. Other solution would be to implement a abstract getA/B for every instance, returning the proper match for each one. Not the end of the world – unless you have no idea why one of your thousands of enum references is null in the middle of a immense code base.

5. Enums inheritance

This is a far more known problem; who has never tried to create an inheritance chain of enums? Well, javac says you can’t:

public enum A {
    A1, A2;

    public enum B extends A {}
}

 

Gives us a syntax error. Actually, this is a very reasonable error. Having any kind of extension on a enum just breaks its entire purpose. What constants would you add to B, if this compiled, for instance?

If we have a method that takes an A, we look at A’s declaration and we know all possible values. We can even switch on them! That’s the beauty of enumerations. But if we allow someone to extends A, they would be able to add more constants. That just doesn’t make sense, whatsoever.

One reason why one would want to do this is to allow some set of enums to have similar functionality. You can express the similarity with interfaces; since they are not concrete, there is no problem in an enum implementing them. You just need to make sure to implement the methods. In order to share the implementation, just extract the code somewhere else, like a static method.

There is not much to be discussed. Extending is infeasible, the workaround is not the best but it’s very simple. But at least you can implement interfaces with enums right? Which leads us to…

6. Annotations inheritance

Well, unlike enums that are classes, annotations are interfaces. So it would make no sense for them to extend concrete classes. But why can’t they extend interfaces? Or at least other annotations? Well, because not. Since they original purpose was documentation, the Java Gurus thought that would be way to much complexity and would not be worth it. AFAIK, there is no design problem that wouldn’t allow for this. Of course back on Java 1.5 it was impossible to predict the importance and the role that annotations would have taken as meta-data providers for Reflection and as integral part of the Annotation Preprocessing ecosystem, just like no one would’ve guessed how important the computer, the Internet or chocolate would become to modern civilized life.

This

public @interface A {
    public @interface B extends A {}
}

 

gives error: 'extends' not allowed for @interfaces.

This is probably one of my greatest disappointments with Java. But that certainly doesn’t mean we should give up on doing it. The best solution I found is to user annotations to our advantage, and actually annotate annotations with annotations. Yeah, that’s right, you can do that.

Of course you’ve done it already, because Java has its built in annotations that you must use to create new ones, like Retention or Target. But you might not have thought of using your own custom annotations as meta-annotations to replace inheritance. Suppose you wanted all your validation annotations to be somewhat connected; instead of making them all extend an annotation, you can mark then all with a custom meta-annotation, and required “fields” can become properties of that annotation.

If what you want is to inherit properties, you can use composition instead of inheritance, which is typically a better practice anyway. So, for example, if we wanted all our animals annotations (don’t ask) to share some properties, we can extract then to another one. So we would have the very same Animal interface:

public @interface Animal {

    public String name();
    public AnimalType tpe() default AnimalType.MAMMAL;
    public double weight();
}

 

But instead of inheritance:

public @interface Cat extends Animal {
    public Color furColor();
}

 

Just use composition:

public @interface Cat {
    public Animal animal;
    public Color fur();
}

 

To invoke this annotation, one would just use the following syntax:

@Cat(animal = @Animal(name = "Kitty", weight = 10.5), fur = Color.GRAY)
public void doit() { /**/ }

 

Not the cleanest syntax, but, hey, it works. So of the inheritance goodies, we replace the interface part with meta-annotations, and the extension part with composition.

Entre em Contato

Your message was sent successfully. Thanks.

Tags

Comments