Java Generics and Type Safety

When I learned to code in Java, there was no such thing as generics to ensure type safety. Casting objects was part of the routine, and CastClassException was a familiar message. But Java now comes with Generics to help us avoid those runtime exceptions (when the application runs). Generics look like MyClass. Instead of having runtime exceptions, the compiler shows errors. Generics specify the type of what is within a container class (in this case MyClass). For example, we can define Cart to represent a cart of product from a shopping website.

Here are a few guidelines to use them:

1. Avoid using raw type. It is only there for backward compatibility. If necessary, use unbounded wildcards.

Cart cart; --> raw type: No!
Cart<?> cart; --> Unbounded wildcard type: Better!
Cart<E extends Item> --> Bounded type parameter: Better!
Cart<Item> cart; --> Generic: Better!

Wildcards are useful to ensure type safety even when the type is unknown. However, we cannot assume the type of object that we get out of our container… and we cannot put any element (other than null) into our container. If these restrictions are unacceptable, we can use generic methods or bounded wildcard types.

Cart<?> cart = Cart.empty();
cart.add(something); --> do not compile
Object something = cart.get(0); --> cannot assume the type of something

Unbounded wildcards are ok when nothing specific to the element type is used. For example, list.size() does need to know the type of objects in the list.

If for whatever reason, you use a raw type, a good practice is to test before with instanceof or isAssignedFrom.

2. Remove unchecked warning. If for whatever reason, you use raw types or cast such as:

Set<E> exaltation = new HashSet();
Set exaltation = new HashSet<>();

Add @SuppressWarnings(“unchecked”) on the smallest scope possible. For example, add the annotation on a method instead of a whole class. Otherwise, it will mask warnings you need to see. Also comment to explain why it is safe.

3. Use generic types – obviously – whether generic classes or methods. A static method can even be generic:

static <E> List<E> asList(E[] a)

However, a generic class cannot infer a static method, which means that:

class Cart<E extends Item> {
   public add(E item) {
     // E must extend Item because of the class declaration
     …
   }

   public static <E> List<E> asList(E[] a) {
     // E here does not depend from the class declaration.
     // the solution is: <E extends Item> static List<E> asList(E[] a)
     …
   }
}

4. Use bounded wildcard to add flexibility. Bounded wildcards look like: Iterable. It specifies the possible boundaries of the parameters. Let’s illustrate this. We want to create a Cart class:

public class Cart<E> {
   public Cart();
   public void add(E e);
   public E pop();
   public boolean isEmpty();
   public void addAll(Iterable<E> src) {
      for (E e : src)
         add(e);
      }
   }
}

Cart<Item> cart = new Cart<>();
Iterable<Fruit> fruits = … ; // Fruit extends Item
cart.addAll(fruits); // Won't work because Iterable<Fruit> cannot be converted to Iterable<Item>

The solution is:

public void addAll(Iterable<? extends E> src)

Use wildcard types on input parameters. Avoid bounded wildcard types as return types. Instead of providing flexibility, it would force you to use wildcard types in client code. You should not need to think about wildcards in the client code. If you have to return a wildcard, remember: Wildcards means “anything” so treat it that way. It implies you do not need to know what is manipulated. For example:

Cart<?> getCart();

It may be ok if what you do is simply call methods on the Cart object that can be type agnostic, such as getting the total sum of the cart:

Cart<?> cart = getCart();
double sum = cart.getSum(); // does not depend on the type of product in the cart

if a type parameter appears only once in a method declaration, replace it with a wildcard. If it’s an unbounded type parameter, replace it with an unbounded wildcard; if it’s a bounded type parameter, replace it with a bounded wildcard.

Generics are great, but it can quickly get messy with polymorphism… but this is for another post.

Browsing folders with Kotlin

Kotlin offers significant improvements to Java. But coming from a Java background, it can sometimes get tricky. I was looking at browsing folders and I found Kotlin’s method walkTopDown:

fun File.walkTopDown(): FileTreeWalk

I used it recursively to find pom.xml files.

fun findPomFiles(
        folder: File,
        pomTrees: MutableList,
        includeDependencyManagement: Boolean,
        searchSubFolders: Boolean
    ): MutableList {

        // find pom file in the current folder
        val pomFile = folder.listFiles().find { it.name == "pom.xml" }

        pomFile?.let {
            println("Found pom file in $folder")
            pomTrees.add(PomNode(pomParser.deserialize(it), includeDependencyManagement))
        }

        if (searchSubFolders) {
            folder.walkTopDown() // HERE IS THE METHOD
                .filter { it.isDirectory && it != folder && it.name != "target" && it.name != "src"} // ignore src and target folders for performance
                .forEach {
                    findPomFiles(it, pomTrees, includeDependencyManagement, searchSubFolders)
                }
        }

        return pomTrees
    }

I also found the function onEnter of FileTreeWalk that can be used to avoid exploring useless branches.

fun onEnter(function: (File) -> Boolean): FileTreeWalk

folder.walkTopDown() // HERE IS THE METHOD
    .onEnter { it.name != "target" && it.name != "src"}

However, the result was not what I expected. The program was looking at the folders multiple times. I realize walkTopDown is not made for exploring folders recursively.
What it actually does is to browse folders and for each folder, we can do whatever we need to.

So two possibilities:

A. keeping the code recursive and using listFiles() from File – like we used to do it in Java

    if (searchSubFolders) {
        folder.listFiles()
            .filter { it.isDirectory && it != folder && it.name != "target" && it.name != "src"} // ignore src and target folders for performance
            .forEach {
                findPomFiles(it, pomTrees, includeDependencyManagement, searchSubFolders)
            }
    }

B. using walkTopDown

fun findPomFiles(
        folder: File,
        pomTrees: MutableList,
        includeDependencyManagement: Boolean,
        searchSubFolders: Boolean
    ): MutableList {

        // find pom file in the current folder
        addPomNode(folder, includeDependencyManagement)?.let { pomTrees.add(it) }

        if (searchSubFolders) {
            folder.walkTopDown()
                .onEnter { it.name != "target" && it.name != "src" }
                .forEach {
                    addPomNode(it, includeDependencyManagement)?.let { pomNode -> pomTrees.add(pomNode) }
                }
        }

        return pomTrees
    }

    fun addPomNode(folder: File, includeDependencyManagement: Boolean): PomNode? {
        val pomFile = folder.listFiles()?.find { it.name == "pom.xml" }

        pomFile?.let {
            println("Found pom file in $folder")
            return PomNode(pomParser.deserialize(it), includeDependencyManagement)
        }

        return null
    }

Storing configuration: Property files vs Constants

I had to add some features in a report. The report is configured in a context class written in Java. Fields and other configurations are hard coded as variables. It was the opportunity to update the code to avoid refactoring each time something new was needed. I created a property file and a parser. Now it was all good to go… BUT! mistake on my behalf. This application was not a web application, but a heavy client written with Netbeans Platform. I jumped into this property file by force of habit. A property file does not fit a heavy client well. Why?

# CONFIGURATION for ReportX

# field definition configuration
my.report.field.property1=123
my.report.field.property2=345
my.report.field.property3=456

# calculation configuration
my.report.calculation.configuration1=property1+property2-property3
my.report.calculation.configuration2=property1-property2-property3
my.report.calculation.configuration3=property1*property3

Pros:

  • No code to change.
  • Configuration easy to change without compiling, packaging, deploying and restarting the application.
  • Compact appearance.

Cons:

  • Configuration mistakes not easy to detect. Typo or missing configuration are detected by IDE in the case of global constants.
  • Parser code more complex than listing constants.
  • Configuration format needs to be defined somewhere.
  • In the case of a heavy client, users can potentially update the file even if it is included in a jar file.
  • In the case of a heavy client, changing the property file still implies deploying it on all the machines => which voids the greatest benefit of having a property file.

In conclusion: context matters. Unfortunately, one size does not fit all – especially when it comes to programming. In this case, a property file is not helpful and more prone to errors than constants.