0

I have a generic class that looks similar to this

public class NetworkItems<T> { private Status status; private T items; public NetworkItems() { this.status = Status.FAILURE; this.items = null; } public NetworkItems(Status status, T listItems) { this.status = status; this.items = listItems; } public NetworkItems(Status status) { this.status = status; this.items = null; } public Status getStatus() { return status; } public void setStatus(Status status) { this.status = status; } public T getItems() { return items; } public void setItems(T items) { this.items = items; } } 

All I want to do is check if the parameter T is a List of any kind in the constructors. If T is a List<> then I want to instantiate it into a new List<>();

I tried the following code

if (this.items instanceof List) { this.items = Collections.emptyList(); } 

or this

this.items = new ArrayList<>(); 

But I keep getting an error because I couldn't give a parameter type. How do I make sure that I instantiate the items with a new List if the generic type T is a List?

4
  • 1
    If you plan on hard-coding a dependency on list, then why not just use NetworkItems<List>? Commented May 2, 2018 at 11:15
  • Because the container should be able to host both list of items and a standalone item. Commented May 2, 2018 at 11:28
  • @SriramR Because the container should be able to host both list of items and a standalone item - why should it? Why not have two different containers for single item or collection of items? Commented May 2, 2018 at 11:39
  • I didn't wanna repeat code. The implementation is the same. Except for the T part. So I thought if there's a way to do without repeating code, why not do it? Commented May 2, 2018 at 11:49

3 Answers 3

1

Give the class a non-optional constructor argument of type Supplier<T>.

public class NetworkItems<T> { private Status status; private T items; private Supplier<T> defaultCreator; public NetworkItems(Supplier<T> def) { this.status = Status.FAILURE; this.items = null; this.defaultCreator = def; } public T createDefault() { return defaultCreator.get(); } // ... 

Now, if you have an instance of NetworkItems, you can always get a default value. Eg,

NetworkItem<List<String>> stringListItems = new NetworkItem<>(ArrayList::new); List<String> defItem = stringListItems.createDefault(); 
Sign up to request clarification or add additional context in comments.

Comments

0

You can just add a type cast, then it should work like you already said:

if (this.items instanceof List) { this.items = (T) Collections.emptyList(); } 

4 Comments

It gives an UncheckedCastException warning.
Yes, that's true but I think you cannot prevent this if you use such generic member variable because the constructor cannot know at compile time which type you want to use there. Maybe you can use another approach, instead using just T items you can use direcly a list List<T> items; where you add your items.
Also even if T is List<Something>, this.items may still be null so instanceof won't help much.
Yeah, I did use it earlier as List<T>. The thing is I want this container to be able to hold a List<> and an Object. So I just wanted to know if its possible without writing a new Holder.
0

Based on comments herein and your original post, it seems like items is intended as a collection regardless of your situation. Would you not be better suited to do the following?

 public class NetworkItems<T> { private Status status; private List<T> items; //continue the remainder of your implementation here } 

I understand this is not ideal for the scenario where 1 item can exist, but you ensure type safety here and adhere to the concept of this can be one or more items, by making items a collection.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.