Tag Archive for 'cast'

Java Tips: Using generic correctly

Generic is very powerful tools, it allows us to get errors that usually only happen in runtime to compile time like the usual type error.

Generic is also very tempting and in normal case, is very easy to use in daily programming. But without a good thinking, we normally will lose the actual power of generic. Let’s we start with this bad news.

The last article I referred on article Java Tips: Iterate and cast is one example where we wrote a Java code using generic but not optimally. The code is as follow:

@SuppressWarnings("unchecked") public static <X> X cast(Object o) {
    return (X) o;
}

What’s wrong with that? PPOW show the wrong cases to us.

Number telephoneNumber = cast("1234567");

session.setAttribute("digits", setOfDigits);
List<Character> characters = cast(session.getAttribute("digits"));

String authorName = cast(session.getAttribute("authorId"));

The errors that we usually get in compile time are missed and can only be get in runtime.

How to make it correct? It is actually pretty simple if we think it through. The essence of casting is to specify that certain superclass that we have is actually a subclass. This relationship is important. Knowing that we know that the argument of the method should be superclass of the result, and not an arbitrary object. So we can fix our method cast like following.

@SuppressWarnings("unchecked") public static <T, X extends T> X cast(T o) {
	return (X) o;
}

And now try all the cases PPOW suggested and we will get an error in compile time. That’s good!

The last case PPOW suggested in the article is not really valid because even using a not tricky techniques, the error will only be happen in runtime. These codes compile correctly but all have problem in runtime.

Using original code:

// Because of an error we cast it to a map of String to String
Map<String, String> badMap = cast(session.getAttribute("map"));

// we pass the map between many objects and doing many operations on it
String s1 = badMap.get(1);
badMap.put("2", "2");
String s2 = badMap.get("2");
String s3 = badMap.get(2);
String s4 = badMap.get(123);

Using modified code:

// Because of an error we cast it to a map of String to String
Map<String, String> badMap2 = cast2(session.getAttribute("map"));

// we pass the map between many objects and doing many operations on it
String s1a = badMap.get(1);
badMap.put("2", "2");
String s2a = badMap.get("2");
String s3a = badMap.get(2);
String s4a = badMap.get(123);

Using normal cast:

// Because of an error we cast it to a map of String to String
Map<String, String> badMap3 = (Map<String, String>)(session.getAttribute("map"));

// we pass the map between many objects and doing many operations on it
String s1b = badMap.get(1);
badMap.put("2", "2");
String s2b = badMap.get("2");
String s3b = badMap.get(2);
String s4b = badMap.get(123);

As you can see, generic is easy to implement, but to implement it correctly is not that easy. I really suggest to read the white print of generic which honestly, I still don’t understand the whole of it. The latest edition of Effective Java also has some tips to work with generic.

Learn generic, it is worth it!

Java Tips: Iterate and cast

… (or More on cast away with Java generics)

Question: How many times did you encounter this kind of code?

List<Element> l = ...;
for (Element e : l) {
   if (e instanceof SubElement) {
      SubElement se = (SubElement) element;
      // do something
   }
}

If you get that so often, what do you think about this code?

List<Element> l = ...;
for (SubElement se : filter(l)) {
   // do something
}

Nice, huh?

I came across this idea after reading an article Cast away with Java generics. The article suggests a nice approach to cast.

    @SuppressWarnings("unchecked") public static <X> X cast(Object o) {
        return (X) o;
    }

And then you can use it to change an ugly code of:

Session webappSession;
        Map<String, Map<String, Collection<Entity>>> myUglyMap = (Map<String, Map<String, Collection<Entity>>>) (webappSession
                .getAttribute("myUglyMap"));

to a slightly better code:

Session webappSession;
        Map<String, Map<String, Collection<Entity>>> beautiful = cast(webappSession.getAttribute("beautiful"));

To get the nice iteration like I presented in the beginning of the article, I created two methods that reuse this cast method. Here they are:

   public static <X, T extends X> Iterable<T> filter(final Iterable<X> iterable) {
        return new Iterable<T>() {
            @Override public Iterator<T> iterator() {
                return new Iterator<T>() {

                    private T t = null;

                    @Override public boolean hasNext() {
                        while (iterable.iterator().hasNext()) {
                            try {
                                t = cast(iterable.iterator().next());
                                return true;
                            } catch (ClassCastException e) {}
                        }

                        return false;
                    }

                    @Override public T next() {
                        if (t == null) {
                            while (iterable.iterator().hasNext()) {
                                try {
                                    return cast(iterable.iterator().next());
                                } catch (ClassCastException e) {}
                            }
                        }

                        return t;
                    }

                    @Override public void remove() {
                        iterable.iterator().remove();
                    }
                };
            }
        };
    }

    public static <X, T extends X> Iterable<T> filter(final X[] iterable) {
        return new Iterable<T>() {

            @Override public Iterator<T> iterator() {
                return new Iterator<T>() {

                    private int index = 0;

                    @Override public boolean hasNext() {
                        while (index < iterable.length) {
                            try {
                                @SuppressWarnings("unused")
                                T element = cast(iterable[index]);
                                return true;
                            } catch (ClassCastException e) {}
                            index++;
                        }
                        return false;
                    }

                    @Override public T next() {
                        while (index < iterable.length) {
                            try {
                                return cast(iterable[index++]);
                            } catch (ClassCastException e) {}
                            index++;
                        }
                        return null;
                    }

                    @Override public void remove() {
                        throw new UnsupportedOperationException();
                    }
                };

            }

        };
    }

The down side is of course you may have problem with performance because of ClassCastException. But I haven’t profiled it… yet.