Java generics for optional single value or collection


Java generics for optional single value or collection



I'm trying to define a container for a whole bunch of classes as some parts of the code will make more sense with a collection but other places will make sense with single values.



Ideally I'd like to do this:


public class AllModes<T> {
private T<Car> car;
private T<Boat> boat;
private T<Train> train;
private T<Plane> plane;
...40 more of these...
}



then I'd like to use the class like:


AllModes<List> allModes;
AllModes<Optional> oneOfEachMode;



But I get the error I get is "The type T is not generic; it cannot be parameterized with arguments "



The reason I'm defining these in multiple variables and not a single HashSet based on a superclass is I want to have get methods that return the correct types to avoid consumers of this class needing to cast down everywhere as each object has its own distinct fields.



I also considered just storing a single value list or set but I thought it might less error prone to use the correct type I intended (ie. one value)





You should use T directly rather classes like Car,Boat etc
– Gaurav Srivastav
Jul 1 at 9:12





@GauravSrivastav If I do that how do I define all the different variables I need for each type?
– TownCube
Jul 1 at 9:22





why don't you consider the composite pattern? it looks like it's the case (treating a collection and a single instance in the same way)
– Andrew Tobilko
Jul 1 at 9:25






even if it was possible, how would you initialise these collections? new T() wouldn't work
– Andrew Tobilko
Jul 1 at 9:33


new T()





How do you expect your clients to work with this type? I mean, is there a scenario where a client will want to use AllModes<T> or is it always going to be either AllModes<Optional> or AllModes<List>? If it's the latter, the top-level abstraction is useless and you can have different classes for each container type, not even part of the same hierarchy (if you don't care about DRY); and there will be no need for generics.
– Costi Ciudatu
Jul 1 at 12:24



AllModes<T>


AllModes<Optional>


AllModes<List>




4 Answers
4



You can't solve it this way. Use the instanceof operator instead. Here is an example:


instanceof


public class AllModes<T> {
private T object;

private void check(T object) {
if(object instanceof Boat){
System.out.println("Boat");
// your code for Boat goes here
} else if (object instanceof Car) {
System.out.println("Car");
// your code for Car goes here
}
}
}



You can have multiple types in class and then you can associated them with the fields. But in your case you have several fields with some type. A class don't have much dependencies on others. You should design you class in a way that there are no much dependencies there.


public class AllModes<T,T1,T2,T3> {
private T car;
private T1 boat;
private T2 train;
private T3 plane;

}





AllModes<HashSet<Car>, HashSet<Boat>, ...> might be fine (actually, no), but how are you going to init the T, T1 ... fields?
– Andrew Tobilko
Jul 1 at 9:39



AllModes<HashSet<Car>, HashSet<Boat>, ...>


T


T1





AllModes<Car, Boat, Train, Plane> allModels = new AllModes<>(); But I think you need one at a time. Do you want to put some default values for your fields ?
– Gaurav Srivastav
Jul 1 at 9:42






how does a car get initialised in the non-argument constructor? I would like to see a complete filled instance of this class. not just a version that compiles.
– Andrew Tobilko
Jul 1 at 9:45



car





These are just 4 unrelated types, like in a Tuple4. i.e. the following compiles fine: new AllModels<List<Car>, Optional<Boat>, Train, String>()
– Costi Ciudatu
Jul 1 at 11:14



Tuple4


new AllModels<List<Car>, Optional<Boat>, Train, String>()



You can't achieve what you want using the Java type system.
Since you can't have a generic container type, you'll need to enforce the invariants with dedicated constructors (or subclasses).



But if you do so, the clients of your class will not be able to distinguish between different container types (Optional vs List), they will need to work with a generic abstraction (like Stream, Iterator, Iterable, whatever suits you).


Optional


List


Stream


Iterator


Iterable



Here's an example:


public class AllModes {
private final Supplier<Stream<Car>> cars;
private final Supplier<Stream<Boat>> boats;

public AllModes(Optional<Car> car, Optional<Boat> boat) {
// Assuming Java 8, when Optional did not have a stream() method yet
this.cars = () -> car.map(Stream::of).orElse(Stream.empty());
this.boats = () -> boat.map(Stream::of).orElse(Stream.empty());
}

public AllModes(List<Car> cars, List<Boat> boats) {
this.cars = cars::stream;
this.boats = boats::stream;
}

public Stream<Car> getCars() {
return cars.get();
}

public Stream<Boat> getBoats() {
return boats.get();
}
}



I'd suggest you take a step back and re-consider what exactly you want to achieve with this container. E.g. ask yourself what its domain is or what the client is supposed to do with Allmodes<T>...


Allmodes<T>



Another more concrete question that comes to mind is how exactly you intend to popuplate that Optional<T> generically? Will it be the first element in the List<T> or the last? Or an element which satisfies a specific Predicate<T>?


Optional<T>


List<T>


Predicate<T>



Your design doesn't seem to be that well thought out yet.



What you could do which would come close to what you descibed (in case I got that right) is provide an accessor of type Stream<T> as you could get both a List<T> aswell as an Optional<T> from it. Your client would then have to make that decision and also determine how exactly to derive the Optional<T> from the Stream<T>.


Stream<T>


List<T>


Optional<T>


Optional<T>


Stream<T>





I'm trying to group a bunch of types so I can pass the group around, with type safety and for different use cases (lists in some places, single values in others). For example one part of the code would need to be able to pull down all the cars, however another part just wants to have one of each mode (eg. populated off a request based form). I'm aiming to reduce duplication (ie. if a new mode was added it doesn't need to be added to both a list and single version of the grouping class)
– TownCube
Jul 1 at 13:43






@TownCube sounds to me like the smallest common denominator between List and Optional or not? Maybe just use a list with one element. An Option type can be converted into a List with at most one element and back. The vavr library supports this. It's actually Value which supports it.
– Rea Sand
Jul 1 at 21:25



List


Optional


Option


List






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

List of Kim Possible characters

Audio Livestreaming with Python & Flask

NSwag: Generate C# Client from multiple Versions of an API