3

I have a data structure that stores various permission groups for a multiplayer game server. There is an instance of a "Rank" class for each permission group. Each rank also has a name. I need to be able to access all of the ranks both in a Iterable fashion and with a key.

There are three main ways I can think of doing this. I don't know which one is best as they all have pros and cons. The first method could have a significant performance impact as the getRank(String) method will be called quite often with anywhere from about 2-50 ranks. The second method could also be problematic as there are several instances, although not nearly as common, where it is useful to have such a method with high performance. The third method could be problematic if the list and map ever get out of sync, especially since it needs to be thread-safe.

I would like to know which method is best and why. My primary concern is that it is both reliable and performant.

Method #1

public synchronized Rank getRank(String name) throws IllegalArgumentException{
    for(Rank rank : ranks){
        if(rank.getName().equalsIgnoreCase(name)){
            return rank;
        }
    }

    throw new IllegalArgumentException("Rank: " + name + " does not exist!");
}

Method #2:

public synchronized List<Ranks> getRanks(){
    ArrayList<Ranks> ranksList = new ArrayList<Ranks();

    for(String rankName : ranksMap.keySet()){
        ranksList.add(ranksMap.get(rankName));
    }

    return Collections.unmodifiableList(ranksList); //unmodifiableList to prevent someone from trying to add or remove ranks by editing this list
}

Method #3:

public class RankList{
    private ArrayList<Rank> list = new ArrayList<>();
    private Map<String, Rank> map = new HashMap<>(); 

    public void add(Rank rank){
        list.add(rank);
        map.put(rank.getName().toLowerCase(), rank);
    }

    public List<Rank> getRanks(){
        return Collections.unmodifiableList(list);  
    }

    public Rank get(String name){
        return map.get(name.toLowerCase());
    }

}
  • 1
    Do you order by insertion order or something else? A list allows you to reorder elements, and the distinction is very important. – user22815 Oct 6 '15 at 3:41
  • @Snowman I don't care what the order is. – john01dav Oct 6 '15 at 3:59
6

If you order elements by insertion order, you can use Java's LinkedHashMap

You will not be able to view it as a list, but you can easily siphon data into a temporary list and return that list. From there you can sort it if necessary.

You can also use a SortedMap (TreeMap is its standard implementation) if you want to have the map in a specific order. You can return a list view the same way, copying data into a list via iterator.

Member variable declaration would be one of the following:

// Need insertion order
private Map<String, Rank> map = new LinkedHashMap<>();
// Need key order or some other order (can pass in comparator)
private Map<String, Rank> map = new TreeMap<>();
// Do not care about order.
private Map<String, Rank> map = new HashMap<>();

You would return the list one of these ways:

// Using map order or do not care about order.
public List<Rank> getRanks() {
  return new ArrayList<Rank>(map.values());
}

// Using some other order.
public List<Rank> getRanks() {
  List<Rank> values = new ArrayList<Rank>(map.values());
  Collections.sort(values); // can pass in comparator
  return values;
}

NB: I know you said order does not matter, but I am covering all the bases for other readers who might find this information useful.

See also:

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.