Sebastian Barth
Sebastian Barth

Reputation: 4517

Restrict types in Java for use in a List

How can I pass a List<T> with a set of certain allowed types I did not declare to a method.

E.g. Restrict types to Integer, Boolean and String:

// Pseudo code
public void method(List<Integer OR Boolean OR String> myList);

If I use List<Object> I can put everything into that list:

public void method(List<Object> myList);

If I use List I can put all instances of Parent and its subclasses into that list:

public void method(List<Parent> myList);

That would be enough if I am the one who declares those subclasses (AllowedTypeA extends Parent). But what can I do when I'm not the owner of the classes I want to use (I cannot make Integer extend Parent)?

Upvotes: 6

Views: 3353

Answers (2)

Compass
Compass

Reputation: 5937

Conceptually, I would prefer @laune's solution much more. I'd prefer type safety and compile errors over willy-nilly throwing a bunch of things into a list and forgetting to add the permitted Type.

That being said, it is still possible to do, though you'll have to do a bunch of extra stuff to make this practical, i.e. if you remove the object type, you should also probably remove all objects that are associated with it, and the other methods need to be overridden such as addAll to ensure proper functionality.

This approach makes it more flexible compared to laune's though, because you can add permittedTypes at any time. For your situation, probably not the best, but the general question is still intriguing enough that I took a shot. Maybe you want some of your Lists to store Integers, but not others. You can do so using the addPermittedObject method.

public class SelectiveList extends ArrayList<Object> {
    //the (types of) objects that we can store
    private ArrayList<Object> permittedObjects = new ArrayList<Object>();

    // put an Object type into the list
    public boolean addPermittedObject(Object o) {
        for (Object type : permittedObjects) {
            if (type.getClass() == o.getClass()) {
                return false; // if we already have it, do not add it again
            }
        }
        return permittedObjects.add(o); // else let's add it
    }

    // remove the Object type
    public boolean removePermittedObject(Object o) {
        for (Object type : permittedObjects) {
            if (type.getClass() == o.getClass()) {
                return permittedObjects.remove(type);
            }
        }
        return false;
    }

    @Override
    public boolean add(Object o) {
        for (Object type : permittedObjects) {
            if (type.getClass() == o.getClass()) {
                return super.add(o); // go ahead and add the item since it
                                        // matches our list
            }
        }
        return false;
    }
}

And to test it:

public static void main(String[] args) {
    SelectiveList selectiveList = new SelectiveList();
    selectiveList.add("Potato");
    selectiveList.add(1);
    selectiveList.add(true);
    System.out.println(selectiveList.size()); // prints 0
    // these objects need to be initialized, but their contents do not
    // matter
    selectiveList.addPermittedObject(new String());
    selectiveList.addPermittedObject(new Boolean(false));
    selectiveList.addPermittedObject(new Integer(1));
    selectiveList.add("Potato");
    selectiveList.add(1);
    selectiveList.add(true);
    System.out.println(selectiveList.size()); // prints 3
}

Upvotes: 2

laune
laune

Reputation: 31290

The best thing to do is to wrap this mixed list into a class and provide methods to add just what you want to permit:

class WrappedMix {
    private List<Object> oddsAndEnds = ...

    public void add( Integer el ){ oddsAndEnds.add( el ); }
    public void add( Boolean el ){ oddsAndEnds.add( el ); }
    public void add( String el ){ oddsAndEnds.add( el ); }
}

Or extend ArrayList with suitable overriding (and overloading),

Although I'm curious why you'd want such a List - it's processing isn't convenient.

Upvotes: 7

Related Questions