dcsimg
Collection classes in Java aren't template classes - a workaround
0 posts in topic
Flat View  Flat View
TOPIC ACTIONS:
 

Posted By:   Jon_Thorarinsson
Posted On:   Monday, March 4, 2002 05:22 AM

The following idea is very simple although this may seem to be a bit long explanation. If you want to see the idea - the solution of the problem, before you see the problem, you can take a look at the section below, called " The solution - Workaround 3 - Java typedefs (kind of) ". 1. The problem: I discovered something remotely cool while I was coding in Java again after a very long break from it and being mostly a C++ programmer. I want to share the idea. Because the collection classes List, Set, Map, Collection, HashMap, etc., in Java aren't template classes like their corresponding collection classes in C++ (in the C++ Standard Template Library (stl)), it can sometimes be hard to figure out what kind    More>>

The following idea is very simple although this may seem to be a bit long explanation. If you want to see the idea - the solution of the problem, before you see the problem, you can take a look at the section below, called " The solution - Workaround 3 - Java typedefs (kind of) ".


1. The problem:


I discovered something remotely cool while I was coding in Java again after a very long break from it and being mostly a C++ programmer. I want to share the idea. Because the collection classes List, Set, Map, Collection, HashMap, etc., in Java aren't template classes like their corresponding collection classes in C++ (in the C++ Standard Template Library (stl)), it can sometimes be hard to figure out what kind of objects are stored in collection classes in Java just by looking at variable defnitions. Let's take an example:


-----------------------------------------------------------------------------


import java.util.List;

import java.util.ArrayList;


class Blat

{

    
private List mList = new ArrayList ();

    
...

    
...

}


-----------------------------------------------------------------------------


Now, just by looking at this piece of code, you can't see what kind of objects should be stored in the member variable 'mList'. But when objects are later inserted in the list, they must be of the correct type, always. Also, when they are extracted from the list, they must always be cast to the correct class.


I found out that very regularly, I had to search for an example of an insertion or an extraction from the list, just to see what kind of objects were stored in there . I tend to forget quickly the class of the objects in my collection objects, like 'mList'. Often this is because classes in a package tend to have similar names. I think I'm not the only one that tends to have this kind of mental blackout :). Anyway...


There are at least 2 obvious workarounds for this problem:


1) Rename 'mList' to something more descriptive, like 'mStrings' f.ex., if it's a list of String objects.

2) Put a comment in the line above the definition of 'mList', specifying what kind of objects are stored in 'mList'.


The problem with both of these approaches is that this kind of list is very likely going to be used in other places in the code too, f.ex. as a method parameter somewhere. Here's an example:


-----------------------------------------------------------------------------


class Blat

{

    // A list of String objects

    private List mStrings = new ArrayList ();

    ...

    ...


    // 'strings' is a list of String objects

    void foo(List strings)

    {

        ...

    }

}


-----------------------------------------------------------------------------


The problem is that in every place this kind of list (a list of Strings) is defined, a comment regarding the object type has to be put and/or the name of the variable has to be set to something that specifies the kind of objects in the list. Another problem with using class-descriptive names for collection variables (workaround 2), is that it restricts the naming of collection variables to the type of the objects in the collection. We would like, f.ex., to be able to use the name 'mUserIDs', instead of 'mStrings', even though the user ids are strings, because it's more descriptive for the specific situation.


2. The solution - Workaround 3 - Java typedefs (kind of):


Here's my own idea:


Whenever you want to define a new type of collection class, like a List of Chat objects, or a Map from String objects to Integer objects, use a pattern that could be described as "Java typedefs", which improves code readability. It's a pattern that I thought of myself. Maybe you guys know of a better one. If so, I would like to know it.


Let's take an example: Let's say that you want to define a List of String objects and use that kind of collection class in several places in your code. Here's how you would do it (the bulk of the idea is encapsulated in boldface):


-----------------------------------------------------------------------------


import java.util.List;

import java.util.ArrayList;


// List of String objects.

// use: String_List list = new String_ArrayList();

interface String_List extends List{}

class String_ArrayList extends ArrayList implements String_List{}


class Blat

{

    String_List mUserIDs = new String_ArrayList();

    ...

    ...


    void foo(String_List userIDs)

    {

        ...

        String user = "wv:jong@wv.oz.com";

        userIDs.add(user);

    }

}


-----------------------------------------------------------------------------


As you can see in boldface, I'm defining a new interface, "String_List", which extends the interface java.util.List and provides an empty class body - which is important. I'm also defining a new class, "String_ArrayList", which implements the new interface and extends the java.util.ArrayList class (which is the most commonly used concrete implementation of the java.util.List class). This class also provides an empty class body. Similar things could just as easily be done with other concrete implementations of the java.util.List class, like java.util.LinkedList, for example.


Now, you must understand that because the class bodies are empty, this doesn't really do anything at all, code wise. But it sure makes it easier to see what kind of objects are stored in the list. All you have to do is look at the name "String_List" to see that this must be a list of Strings. This, of course, doesn't guarantee correct insertion and extraction of the correct class of objects like the C++ Standard Template Library does at compile time, but it does give you something extra in addition to just typing "List userIDs", in terms of readability. It's also very simple to do this.


Here's an example of how you could do this with the java.util.Map class:


-----------------------------------------------------------------------------


import java.util.Map;

import java.util.HashMap;


// Map from Integer objects to String objects.

// use: Integer2String_Map m = new Integer2String_HashMap();

interface Integer2String_Map extends Map{}

class Integer2String_HashMap extends HashMap implements Integer2String_Map{}



class Blat

{

    Integer2String_Map mGrabbedRegexps = new Integer2String_HashMap();

    ...

    ...


    void foo(Integer2String_Map grabbedRegexps)

    {

        ...

        mGrabbedRegexps.putAll(grabbedRegexps);

        mGrabbedRegexps.put(new Integer(5), "aaabbb");

    }

}


-----------------------------------------------------------------------------


Here's an example of how you could do this with the java.util.Set class:


-----------------------------------------------------------------------------


import java.util.Set;

import java.util.HashSet;


class Chat{ ... }


// Set of Chat objects.

// use: Chat_Set s = new Chat_HashSet();

interface Chat_Set extends Set{}

class Chat_HashSet extends HashSet implements Chat_Set{}


class Blat

{

    Chat_Set mExpiredChats = new Chat_HashSet();

    ...

    ...


    void foo(Chat_Set newChats)

    {

        ...

    }

}

   <<Less
About | Sitemap | Contact