Tuple и Java... Возможно ли? Да конечно. Google поиск выдает первой строкой http://javatuple.com. Здесь реализация а ля Вандервуд и Джосати. Эти корифеи С++ известны своим изданием книги:
"Шаблоны С++. Справочник разработчика."
А причем здесь С++, - cпросите вы. Ответ прост. Для реализации Tuple в Java, используется точно такой же принцип как и в С++.
А именно:
public class Tuple<Type1, Type2> {
public Type1 type1;
public Type2 type2;
};
например такая декларация
Tuple<String, Integer> pair;равносильна следующему классу:
public class Tuple {
public String type1;
public Integer type2;
};или вот пример для трех элементов
Tuple<String, Tuple<Integer, Boolean>> triple;по аналогии
public class Tuple {
public String type1;
public Tuple<Integer, Boolean> type2;
};но к сожалению чем больше элементов в Tuple тем сложнее читать код.
Tuple<Tuple<String, Integer>, Tuple<Boolean, Tuple<Double, Long>>> quintuple; //пять элементов.
String element1 = quintuple.type1.type1;
Integer element2 = quintuple.type1.type2;
Boolean element3 = quintuple.type2.type1;
Double element4 = quintuple.type2.type2.type1;
Long element6 = quintuple.type2.type2.type2;это все выглядит не очень читаемо. Конечно можно написать еще кучу дополнительного кода что бы легко было манипулировать с данными.
public static <Type1, Type2> Tuple<Type1, Type2>
make(Type1 type1, Type2 type2) {
Tuple<Type1, Type2> tuple = new Tuple<Type1, Type2>();
tuple.type1 = type1;
tuple.type2 = type2;
return tuple;
}
...
public static <Type1, Type2, Type3, Type4, Type5> Tuple<Tuple<Type1, Type2>, Tuple<Type3, Tuple<Type4, Type5>>>
make(Type1 type1, Type2 type2, Type3 type3, Type4 type4, Type5 type5) {
Tuple<Tuple<Type1, Type2>, Tuple<Type3, Tuple<Type4, Type5>>> tuple = new Tuple<Tuple<Type1, Type2>, Tuple<Type3, Tuple<Type4, Type5>>>();
quintuple.type1 = new Tuple<Type1, Type2>();
quintuple.type1.type1 = type1;
quintuple.type1.type2 = type2;
quintuple.type2 = new Tuple<Type3, Tuple<Type4, Type5>>();
quintuple.type2.type1 = type3;
quintuple.type2.type2 = new Tuple<Type4, Type5>();
quintuple.type2.type2.type1 = type4;
quintuple.type2.type2.type2 = type5;
return tuple;
}
...
по моему это выглядит ужасно.
Меня не покидала мысль как можно сделать Tuple доступнее для понимания и чтения.
В конце концов родился следующий вариант:
public class Tuple2<Type1, Type2> {
public Type1 type1;
public Type2 type2;
}
public class Tuple3<Type1, Type2, Type3> extends Tuple2<Type1, Type2> {
public Type3 type3;
}
public class Tuple4<Type1, Type2, Type3, Type4> extends Tuple3<Type1, Type2, Type3> {
public Type4 type4;
}...
и т.д.
Ну как? Лучше?
Здесь я ушел от принципа бесконечной рекурсии Generic-a, заменив рекурсию на ручное создание классов.Но, так-как первый способ требует создания большого количества вспомогательных функции или классов, из-за сложности чтения кода, то я считаю что затраты оправдывают себя.
Не менее интересны вопрос - это область применения Tuple. Одна из возможностей - объединять данные в структуру без декларации оной, так сказать, на лету. Самый примитивный способ использования этих структур как return тип. Не знаю как вам, но мне часто хотелось вернуть из функции(, метода и т.д.) больше чем одну переменную.Например:
static Tuple2 split(String input) {
String[] splited = input.split(",");
// здесь вместо комментария проводим проверку или нет :)
Tuple2 output = new Tuple2();
output.type1 = Integer.valueOf(splited[0]);
output.type2 = splited[1];
return output;
}
почему не так:
statis String split(String input, Integer i);или так
statis Integer split(String input, String out);или вот как
statis Object[] split(String input);думаю вопрос не стоит:)
и на ходу рабочий пример:
public class Tuple {
static class Tuple2<Type1, Type2> {
public Type1 type1;
public Type2 type2;
}
static class Tuple3<Type1, Type2, Type3> extends Tuple2<Type1, Type2> {
public Type3 type3;
}
static class Tuple4<Type1, Type2, Type3, Type4> extends Tuple3<Type1, Type2, Type3> {
public Type4 type4;
}
static Tuple2<Integer, String> split(String input) {
String[] splited = input.split(",");
Tuple2<Integer, String> output = new Tuple2<Integer, String>();
output.type1 = Integer.valueOf(splited[0]);
output.type2 = splited[1];
return output;
}
public static void main(String... args) {
final Tuple2<Integer, String> splited = split("10,number");
System.out.println(String.format("This is %s %d", splited.type2, splited.type1));
final Tuple3<String, Integer, Boolean> tuple3 = new Tuple3<String, Integer, Boolean>();
tuple3.type1 = "string";
tuple3.type2 = 10;
tuple3.type3 = true;
System.out.println(String.format("type1: %s, type2: %d, type3: %b", tuple3.type1, tuple3.type2, tuple3.type3));
final Tuple4<String, Integer, Boolean, Double> tuple4 = new Tuple4<String, Integer, Boolean, Double>();
tuple4.type1 = "string";
tuple4.type2 = 10;
tuple4.type3 = true;
tuple4.type4 = 2.5;
System.out.println(String.format("type1: %s, type2: %d, type3: %b, type4: %f", tuple4.type1, tuple4.type2, tuple4.type3, tuple4.type4));
}
}