4

I'm new to Java, and even newer to generics in Java. I have looked for similiar questions, but have found no straightforward answer for my particular problem.

I'm developing a project to manage the patients, doctors, consultations, medical events and all the stuff that is associated with a medical clinic. What I am trying to do right now is to create a list of medical events associated to each patient. To this list of medical events, for now, it is only supposed to be allowed to add exams and prescriptions, but it's supposed to be extendable: I want to be able to add other types of medical events in the future if I need to, such as information about surgeries.

So, I started by creating an ArrayList of generic ArrayLists in the class Patient, with its type bounded to be extended by the class MedicalEvent (so, for now, it's an ArrayList of ArrayLists of type either Prescription or Exam). I also created an ArrayList of type Prescription and another of the type Exam.

List<ArrayList<? extends MedicalEvent>> medicalevents;

private ArrayList<Prescription> prescriptions;

private ArrayList<Exam> exams;

Then, in the constructor, I added the ArrayLists prescriptions and exams to the ArrayList medicalevents.

medicalevents.add(prescriptions);

medicalevents.add(exams);

To add medical events of one of the two allowed types, I defined the following method:

public void addMedicalEvent(E element){

if(element instanceof Prescription){
    medicalevents.get(0).add((Prescription)element);
    }
if(element instanceof Exam){
    medicalevents.get(1).add((Exam)element);
    }
}

The problem is, I get the error "The method add(capture#1-of ? extends MedicalEvent) in the type ArrayList is not applicable for the arguments (Prescription)" and I don't know what it means. Can anyone tell me what I am doing wrong, or suggest a better way to tackle this problem?

Thanks!

3
  • is Prescription is child of MedicalEvent? Commented Dec 1, 2012 at 15:17
  • This is out of topic regarding your question, but I think using a Map<? extends MedicalEvent, List<? extends MedicalEvent>> is way better than having a List of Lists (like you have) that need you to have the indexes hardcoded. Commented Dec 1, 2012 at 15:26
  • You seem to be trying to create a generic heterogeneous collection, which I think is not possible in Java (specially without any compiler warnings regarding type-safety). Commented Dec 1, 2012 at 15:56

2 Answers 2

7

Given following declarations

class A {}
class B extends A {}
class C extends A {}


public class SOSample {
    public static void main(String[] args) {
        List<List<? extends A>> list = new ArrayList<List<? extends A>>();
        final List<? extends A> as = list.get(0);
        as.add(new B()); // error here
    }
}

you can't add B to as, because it will cause problem later on, when you'll try to read from the list:

A a = list.get(0).get(0); // is a B or C?

To better understand this problem there's funny example:

class Vehicle { void launch(); }
class Car extends Vehicle {}
class NuclearMissile extends Vehicle {}
...
// this is prohibited because of below code
List<? extends Vehicle> cars = new ...
// imagine this is possible...
cars.add(new NuclearMissile());
// now this is possible
cars.get(0).launch();

Generally, collections with bounded wildcards like List<? extends Something> are useful for code which won't modify collection, but just iterate over it doing something with elements.

Regarding your original problem -- you can change code so there are two distinct lists, one for Prescription, another for Exam. You still can have just one method which will iterate over these two lists doing something useful (like printing theirs contents):

void doSomethingWithEvents(List<? extends Event> events) {
}
Sign up to request clarification or add additional context in comments.

2 Comments

I think I'll go for the distinct lists. Now that I think about it, that's much simpler and the genericity will be the same. Thanks, that really helped.
There's Oracle Java tutorial on Generics topic: docs.oracle.com/javase/tutorial/java/generics. In addition to other things, it has dedicated page about your question: docs.oracle.com/javase/tutorial/java/generics/inheritance.html and docs.oracle.com/javase/tutorial/java/generics/subtyping.html
1

Would something like this work better?

class Medical {
    List<EventList<?>> eventLists = new ArrayList<EventList<?>>();

    Medical() {
        eventLists.add(new EventList<Perscription>(Perscription.class));
        eventLists.add(new EventList<Exam>(Exam.class));
    }

    boolean add(Object item) {
        for(EventList<?> list : eventLists) {
            if(list.tryToAdd(item)) {
                return true;
            }
        }
        return false;
    }
}

class EventList<T> {
    Class<T> type;
    List<T> list = new ArrayList<T>();

    EventList(Class<T> type) {
        this.type = type;
    }

    boolean tryToAdd(Object item) {
        if(type.isInstance(item)) {
            list.add(type.cast(item));
            return true;
        } else {
            return false;
        }
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.