1

I am new to java and I would like to know how to do this better in java or simpler, cleaner, easier, like having multiple generic types stuff

public class Item<T1, T2, T3, T4, T5, T6, T7, T8, T9>{
    private T1 t1;
    private T2 t2;
    private T3 t3;
    private T4 t4;
    private T5 t5;
    private T6 t6;
    private T7 t7;
    private T8 t8;
    private T9 t9;

    public Item(T1 t1){
        this(t1, null, null, null, null, null, null, null, null);
    }
    public Item(T1 t1, T2 t2){
        this(t1, t2, null, null, null, null, null, null, null);
    }

    public Item(T1 t1, T2 t2, T3 t3){
        this(t1, t2, t3, null, null, null, null, null, null);
    }

    public Item(T1 t1, T2 t2, T3 t3, T4 t4){
        this(t1, t2, t3, t4, null, null, null, null, null);
    }
    ...
14
  • 1
    If you really need a container for nine (!) different gerenic types, then this might actually be the easiest design :D Commented Apr 21, 2017 at 13:58
  • 1
    it depends on what you want to accomplish and how much worth it is to you. Do you want to be able to get the corresponding type via get, e.g. T1 get(1)? Commented Apr 21, 2017 at 14:06
  • 10
    my guess is that you're trying to solve a Problem you didn't tell us about. Post the Problem you are trying to solve and we might be able to assist you. A class with 9 generics will be a total nightmare to use. Don't do it. Commented Apr 21, 2017 at 14:06
  • 1
    I'm sorry but I really need an explication about all this. I can't possibly imagine a case where you need that many generic types in one class. You may have severe design issues on your application. Commented Apr 21, 2017 at 14:08
  • 2
    @Ckkn The issue with your question is that it looks like an XY problem. Such questions tend to receive answers that do not help the OP, until, after a long discussion, people understand the original problem – which often has a well known solution. And everyone just lost their time and energy. Commented Apr 21, 2017 at 14:53

3 Answers 3

1

A couple of suggestions you may find useful:

  1. You have a case of the "telescoping constructor anti-pattern". The builder design pattern is the usual remedy. As you mention you are looking for a simple solution I would recommend using lombok annotations to implement a builder for your class:

    @Getter
    @Builder
    class Item<T1, T2, T3, T4, T5, T6, T7, T8, T9> {
        private T1 t1;
        private T2 t2;
        private T3 t3;
        private T4 t4;
        private T5 t5;
        private T6 t6;
        private T7 t7;
        private T8 t8;
        private T9 t9;
    }
    

    You'd have to initialise an Item like this:

    Item<String, Integer, Double, String, Long, Long, Long, Long, Long> item =
        Item.<String, Integer, Double, String, Long, Long, Long, Long, Long>builder()
                .t4("text").t2(42).t3(3.14159).build();
    

    Unfortunately type information is duplicated. Note that you can skip fields and initialize in any order. That would be a lot of work with multiple constructors. The other fields e.g. t1, t5 will be left null.

  2. Consider adopting Tuple9 from jOOL library. If you look at the source code of Tuple9 it's not simpler than your code. The simplicity of this approach is that someone else has done the implementation instead of you. The library supports up to Tuple16

Sign up to request clarification or add additional context in comments.

Comments

1

You can either use libraries, code preprocessors or the builder pattern, or if you like to keep things simple you might just create chainable methods that would allow you to set only the attributes you want, in whatever order you want:

public class Item<T1, T2, T3, T4, T5, T6, T7, T8, T9> {
    private T1 t1;
    private T2 t2;
    private T3 t3;
    private T4 t4;
    private T5 t5;
    private T6 t6;
    private T7 t7;
    private T8 t8;
    private T9 t9;

    public Item<T1, T2, T3, T4, T5, T6, T7, T8, T9> t1(T1 t1) {
        this.t1 = t1;
        return this;
    }

    public Item<T1, T2, T3, T4, T5, T6, T7, T8, T9> t2(T2 t2) {
        this.t2 = t2;
        return this;
    }

    // TODO: rest of methods
}

Usage:

Item<String, Double, Integer, Long, Long, Long, Long, Long, String> item = new Item()
    .t1("hello")
    .t2(0.123)
    .t3(123)
    .t4(123L)
    .t5(123_456L)
    .t6(123_456_789L)
    .t7(654_321L)
    .t8(321L)
    .t9("goodbye");

Or in any other order:

Item<String, Double, Integer, Long, Long, Long, Long, Long, String> item = new Item()
    .t6(123_456_789L)
    .t2(0.123)
    .t3(123)
    .t5(123_456L)
    .t7(654_321L)
    .t8(321L)
    .t4(123L)
    .t1("hello")
    .t9("goodbye");

Or just with a few attributes:

Item<String, Double, Integer, Long, Long, Long, Long, Long, String> item = new Item()
    .t6(123_456_789L)
    .t2(0.123)
    .t3(123);

Comments

0

Disclaimer: (to stop downvotes ;-))

this is just a simple solution to hold an arbitrary number of objects of different type which are retrievable by an actual type in an, again, simple way without guarantee of type safety. Use with caution!

Proposed solution:

You could just use a simple List<Object>. As you don't want to make clear what your actual requirements are, that might already suffice you... Here is an example:

public class Item {
  List<Object> items = new ArrayList<>();

  public <T> Item(T... items) { // well... could also just be Object
     Collections.addAll(this.items, items);
  }

  public <T> T get(int index) {
     return (T) items.get(index); // unsafe of course... but no requirement said something about type safety ;-)
  }

  public static void main(String[] args) {
    Item item = new Item("sum", 123L, 234L, true);

    if (item.get(3)) {
      long sum = item.<Long>get(1) + item.<Long>get(2);
      System.out.println(item.get(0) + " is " + sum);
    }
  }
}

which prints:

sum is 357

Regarding type safety you could improve that a bit by supplying a type during retrieval and fail miserably if the retrieved object isn't of the expected type:

public class Item {
  List<Object> items = new ArrayList<>();

  public <T> Item(T... items) {
    Collections.addAll(this.items, items);
  }

  public <T> T get(int index, Class<T> type) {
    Object item = items.get(index);
    if (type.isInstance(item)) {
      return type.cast(item);
    }
    throw new RuntimeException("failing miserably as index " + index + " isn't of type " + type);
  }

  public static void main(String[] args) {
    Item item = new Item("sum", 123L, 234L, true);

    if (item.get(3, Boolean.class)) {
      long sum = item.get(1, Long.class) + item.get(2, Long.class);
      System.out.println(item.get(0, String.class) + " is " + sum);
    }
  }
}

As others suggest: a builder pattern might also help, but as soon as you add more types or want to remove some you need to adapt the code. And with the builder pattern you still have to write all that generic type information if you want to declare a variable to hold your item. That isn't necessary with this solution. Of course this solution also has some problems: the first variant isn't type safe and could lead to ClassCastException. The second variant could lead to RuntimeException if you want to retrieve an object which hasn't the given type, but at least it is type safe otherwise ;-) So it really depends on what you want to accomplish.

If you don't like the RuntimeException in the second variant you could also just use an Optional instead. I omitted that variant deliberately as it makes the code just more verbose. Here is the get-implementation for it:

public <T> Optional<T> get(int index, Class<T> type) {
  Object item = items.get(index);
  if (type.isInstance(item)) {
    return Optional.of(type.cast(item));
  }
  return Optional.empty();
}

Finally, I probably wouldn't use this code in production as it is rather a workaround to spare some code. In production code I prefer type safety over such simplicity.

4 Comments

This is totally unsafe code, welcome ClassCastExceptions or RuntimeExceptions
@FedericoPeraltaSchaffner I already mentioned that it isn't type safe. The OP searched for a simple/clean way to solve the generic disaster. The proposed solution is simple. Regarding "clean" it depends. The solution can hold objects of different types and retrieve actual types instead of Object. The second variant throws RuntimeException deliberately and therefore is safer than the first one. Still a simple solution, but it fails if the retrieved object isn't of the expected type. This code can of course still be improved, but: it is complete as it is and doesn't require any libraries.
And yet we still don't know what the OP actually needed to do…
Yes, we do not know it yet. My guess: having something similar as a TupleX (maybe dynamic) but without all that generic types and without using an external library ;-)

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.