Tag: Collections

  • Java Tip #12: Use Collection min()/max() when looking for lowest/highest item in collections

    At work I regularly stumble across a specific type of processing: sorting a collection/list and afterwards only retrieving the first or last element. Such code constructs are clearly for fetching the minimum or maximum element but sorting the whole collection for just a single item seems to be a bit of overhead. And indeed it is and the Collection class provides methods for these purposes without having to juggle items in memory and creating new collection objects which are never really required.


    Advice

    If you have a collection and want to retrieve the minimum or maximum element from it you don’t have to sort it and retrieve the first or last but java.util.Collections offers its min() and max() methods for that which are much more efficient for that exact purpose. These can also be used with custom Comparators.

    Code-Example

    Before

    // retrieve smallest element
    Collections.sort(elementList);
    Element smallest = elementList.get(0);    
    ...
    // fetch item with highest custom value
    Collections.sort(customItemsList, Collections.reverseOrder(new MyCustomComparator()));
    Item largestItem = customItemsList.get(0);

    After

    Element smallest = Collections.min(elementList);    
    ...    
    Item largestItem = Collections.max(customItemsList, new MyCustomComparator());

    Benefit

    Readability gain. Possible huge performance gain, as min()/max() run in O(n) while sorting takes O(n log(n)).

    Remarks

    If the comparison methods (compare(), equals()) do not fulfill the Comparator requirements according to the Java SDK (see here) (i.e. A.equals(B) != B.equals(A) or (A<B)!=(B>A), etc.) then the result of min()/max() may be different than the result from the approach using sorted collections.

  • A trapdoor in Apache Commons CollectionUtils (and its docs)

    A few days ago I hit a problem while refactoring some legacy Java Code. Following my own advice to [use safe and simpler library methods][1] I changed the code-block

    List
    list = dao.getEntries(id); if(list != null && list.size() > 1) { doFancyLogic(list); } to List list = dao.getEntries(id); if(CollectionUtils.size(list) > 1) { doFancyLogic(list); } Should do the same, looks nicer and should be safer too, right? Imagine my confusion when suddenly several unit tests began failing at other parts of the code not directly related to this change. When I found out that this single line was the cause of the other errors I of course looked up the JavaDoc for CollectionUtils on Google. According to the docs at the size() method should return 0 when presented with a null collection. Things were very strange here. In fact, it took me a few days to find out what’s wrong. In fact, I did not recognize that the access to the JavaDoc was redirected to , which did not show the documentation of the latest stable CollectionUtils docs (as it did until a few weeks ago) but showed the version of the SVN tip. It took a roundtrip through the Apache Commons main page to find the correct JavaDoc page for the current stable 3.2.1 CollectionUtils at . And, surprise surprise, there the API for the size() method looks a *bit* different: “Throws: java.lang.IllegalArgumentException – thrown if object is not recognised or null”.
    Well, so much for the praised null-safety of Apache Commons… In the current implementation, CollectionUtils.size() is of no use for me and I reverted the refactoring. In the end I was a victim of partly my own assumptions for the null-safety of Apache Commons and partly a very weird redirection of the Google search result URL. I still have no idea why this URL suddenly gets redirected to a different version than it did until a few weeks ago but I hope that either Google soon updates its search result (unlikely as there are loads of references to this address) or Apache corrects it to its former destination. For the safety of users in my opinion the correct version which shows up should be the one of the latest stable version, not an arbitrary SVN version. Lesson learned: also check version of JavaDoc if something smells fishy, even if it has been correct in the past. [1]: http://kosi2801.freepgs.com/2010/10/02/java_tip_9_use_collectionutils_for_evaluation_and_manipulati.html “Java Tip #9: Use CollectionUtils for evaluation and manipulation of Collections”
  • Java Tip #9: Use CollectionUtils for evaluation and manipulation of Collections

    After quite some time this is another instance of the [Java Tips][1]. It’s an addition to the [Apache Commons][2] related [framework tips][3] which are guiding into the direction that as a developer you should take advantage of existing and proven frameworks and know their features to leverage your development efficiency. This time complexity of the given example is a bit higher than in the previous tips.


    ##Advice Use [Apache CollectionUtils][4] for evaluation and manipulation of Collections.

    ##Code-Example A short spoiler for the following code: This is a routine which checks a given set of categories against a set of category-permissions for a user. The result is a set of categories, which the user is allowed to access.

    Before

    ...
    public boolean hasPermissionsToAccessCategory(String category) {
        return (this.permissions != null && this.permissions.contains(category));
    }
    ...
    
    ...
    public Set
    getCategoriesAllowedToViewBySearchFilter() { Set result = null; if ((this.filter != null && this.filter.getCategory() != null) && (!this.filter.getCategory().isEmpty())) { result = new HashSet (); for (String category : this.filter.getCategory()) { if (this.hasPermissionsToAccessCategory(category)) { result.add(category.toString()); } } if(result.size() == 0) { result = null; } } else { result = this.getAllCategories(); } return result; } …. After … public Set getCategoriesAllowedToViewBySearchFilter() { Set result = null; if (this.filter != null && this.permissions != null && CollectionUtils.isNotEmpty(this.filter.getCategory())) { // get only categories, which are both in permissions and filter categories result = new HashSet (CollectionUtils.intersection(this.permissions, this.filter.getCategory())); // if no results, return null if(result.isEmpty()) { result = null; } } else { result = this.getAllCategories(); } return result; } … ##Benefit Huge readability gain and a safety gain. The code and intention is much clearer here and also has a smaller footprint. The maintainability has been raised because for a developer not familiar with the routine it needs a bit of brainpower to find out what the initial code really does. The removal of the additional method and usage of *CollectionUtils.intersection()* makes it much easier to understand, how the two sets are compared to each other to retrieve the correct results. ##Remarks None if you are initially writing similar logic. If you’re refactoring a method which seems to be better off with framework-provided functionality be careful and think over it a second time. Re-evaluate the code until you’re really sure because it’s easy to overlook a small detail which changes the results for a certain special case. [1]: http://kosi2801.freepgs.com/cgi-bin/mt-search.cgi?blog_id=8&tag=Java%20Tips&limit=20 [2]: http://commons.apache.org “Apache Commons” [3]: http://kosi2801.freepgs.com/cgi-bin/mt-search.cgi?blog_id=8&tag=Java%20Frameworks&limit=20 [4]: http://commons.apache.org/collections/apidocs/org/apache/commons/collections/CollectionUtils.html “CollectionUtils (Commons Collections)”
  • Java Tip #8: Use StringUtils for concatenating Strings from Arrays or Lists

    And we’re continuing with our next Java Tip. Back on using frameworks for our convenience, I present another often useful possibility to let the StringUtils handle lots of work for you.


    ##Advice Use Apache StringUtils for concatenating Strings from Arrays or Lists, also when you need to delimit them with an arbitrary string.

    ##Code-Example Before

    ...
    SQL_WHERE += " AND V.cat_display_name IN (";
    boolean addComma = false;
    for (String category : filter.getCategories()) {
      if (addComma) {
        SQL_WHERE += ", ";
      }
      SQL_WHERE += "'" + category + "'";
      addComma = true;
    }
    SQL_WHERE += ") ";
    ...
    
    ...
    String SQL = "";
    for(String category: filter.getCategories()) {
        SQL += val + ", ";
    }
    SQL = SQL.substring(0, SQL.length()-2);
    ....

    After

    ...         
    SQL_WHERE += " AND V.cat_display_name IN (";
    SQL_WHERE += "'" + StringUtils.join(filter.getCategories(), "', '") + "'";
    SQL_WHERE += ") ";
    ...

    ##Benefit Huge readability gain and a safety gain. The code and intention is much clearer and the possibility to hide bugs in the loop-logic (which I have seen often) is not present. Also, depending on the length of the Array or List, it may also present a small performance gain (see Java Tip #2) but that’s in most such cases neglibigle.

    ##Remarks None.