Purposefully tiny library providing Tuples for Java 8+.
- Immutable
- Supports
null - Easily converted to and from Java collections (Iterables, Maps, Lists, and Sets)
- Parameterized member types
- Comparable, provided member types are
Comparable - Serializable, provided member types are
Serializable
There are only two classes to import, the latter of which is not needed unless you need the factory methods that allow conversions to or from Java collections.
import bdkosher.justuple.Tuple;
import bdkosher.justuple.Tuples;The primary way to create a new Tuple is using the of factory method.
Tuple<Integer, String> tuple = Tuple.of(1, "foo");
assertThat(tuple.getFirst()).isEqualTo(1);
assertThat(tuple.getSecond()).isEqualTo("foo");Instead of passing in the individual members, you can provide a Map.Entry argument.
Map<String, LocalDate> map = ...
Tuple<String, LocalDate> tupleFromEntry = Tuple.of(map.entrySet().iterator.first());You can call of with an Iterable argument, such as List. The Iterable can emit any number of elements but only
the first two will be present in the returned Tuple.
Anything fewer than two elements results in a Tuple with one or more null members.
Input (Iterable<T>) |
Output (Tuple<T, T>) |
|---|---|
[] |
(null, null) |
[1] |
(1, null) |
[1, 2] |
(1, 2) |
[1, 2, 3, 4, 5] |
(1, 2) extra elements ignored |
List<Long> list = ...
Tuple<Long, Long> tupleFromList = Tuple.of(list);Tuples are immutable, but you can create new instances from existing ones using withFirst and withSecond.
Tuple<Integer, String> newTuple = tuple.withFirst(100);
assertThat(newTuple.getFirst()).isEqualTo(100);
assertThat(newTuple.getSecond())
.as("Tuple created using withFirst retains original tuple's second member")
.isEqualTo(tuple.getSecond());
Tuple<Integer, String> newerTuple = tuple.withSecond("bar");
assertThat(newerTuple.getFirst()).isEqualTo(tuple.getFirst());
assertThat(newerTuple.getSecond())
.as("Tuple created using withSecond retains original tuple's first member"
.isEqualTo("bar");The swapped instance method returns a new Tuple with the first and second members swapped.
Tuple<Integer, String> swapped = Tuple.of("foo", 12).swapped();
assertThat(swapped.getFirst()).isEqualTo(12);
assertThat(swapped.getSecond()).isEqualTo("foo");The Tuples class (note the "s" on the end) contains static methods for creating multiple Tuple instances
(note the lack of "s") from a collection/map/stream of individual items.
Use the from factory method to create a List<Tuple<S,S>> from some Iterable<S>. Subsequent elements emitted by
the Iterable are combined into a Tuple. If the overall number of elements emitted is null, the final Tuple
instance will have a null second member value.
Input (Iterable<T>) |
Output (List<Tuple<T, T>>) |
|---|---|
[] |
[] |
[1] |
[(1, null)] |
[1, 2, 3, 4] |
[(1, 2), (3, 4)] |
[1, 2, 3, 4, 5] |
[(1, 2), (3, 4), (5, null)] |
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
List<Tuple<Integer, Integer>> tuples = Tuple.tuplesFrom(list);
assertThat(tuples).hasSize(3);
assertThat(tuples.get(0)).isEqualTo(Tuple.of(1, 2));
assertThat(tuples.get(2)).isEqualTo(Tuple.of(5, null));The from method also accepts a Map<K, V> argument, returning a corresponding Set<Tuple<K, V>>.
Map<String, Integer> map = Map.of("foo", 1, "bar", 2, "baz", 3); // Java 9+
Set<Tuple<String, Integer>> tuples = Tuple.tuplesFrom(map);
assertThat(tuples).hasSize(3);The Tuples.collector() factory methods return a custom Collector that can generate a List of Tuples from a
Stream.
List<String> list = Arrays.asList("foo", "bar", "FOO", "BAR");
List<Tuple<String, String> tuples = list.stream()
.filter(Objects::nonNull)
.collect(Tuple.tupleCollector());
assertThat(tuples).containsExactly(
Tuple.of("foo", "bar"),
Tuple.of("FOO", "BAR")
);A single Tuple instance can be converted into a List.
Tuple<String, Integer> tuple = Tuple.of("Foo", 99);
List<Object> list = tuple.toList();
assertThat(list).containsExactly("Foo", 99);When the Tuple shares the same type for both members, the toTypedList method can be used instead to return a list
parameterized to that type rather than java.util.Object
Tuple<String, String> tuple = Tuple.of("Foo", "99");
List<String> stringList = tuple.toTypedList();
assertThat(list).containsExactly("Foo", "99");Besides lists, a single Tuple instances can be converted to a Map or Map.Entry.
Tuple<Integer, String> tuple = Tuple.of(20, "Bar");
Map<Integer, String> map = tuple.toMapEntry();
assertThat(map).hasSize(1);
assertThat(map.get(20)).isEqualTo("Bar");
Map.Entry<Integer, String> entry = tuple.toMapEntry();
assertThat(entry.getKey()).isEqualTo(20);
assertThat(entry.getValue()).isEqualTo("Bar");The map method converts multiple Tuple<K, V> instances into a single Map<K, V>.
Map<String, Integer> map = Tuple.map(
Tuple.of("foo", 1),
Tuple.of("bar", 2)
);
assertThat(map).containsOnlyKeys("foo", "bar");
assertThat(map.get("foo")).isEqualTo(1);
assertThat(map.get("bar")).isEqualTo(2);If there are multiple tuples with identical keys, the map method will throw an IllegalStateException.
To overcome this problem, use the mapAll method to produce a Map<K, List<V>> instance.
Map<String, List<Integer>> map = Tuple.mapAll(
Tuple.of("foo", 1),
Tuple.of("foo", 2)
);
assertThat(map).containsOnlyKeys("foo");
assertThat(map.get("foo")).contains(1, 2);The zip method combines two arrays/Streams/Iterables into a single List of Tuples. The two arguments to the method
need not be of the same length and can use different data types.
List<Tuple<Integer, Integer>> tuples = Tuples.zip(
IntStream.range(0, 1000).boxed(),
IntStream.range(1, 1001).boxed()
);
assertThat(tuples).hasSize(1000);
int value = 0;
for (Tuple<Integer, Integer> tuple : tuples) {
assertThat(tuple).isEqualTo(Tuple.of(value, value + 1));
++value;
}Instead of providing two individual lists as input, you can also provide a single tuple of lists:
List<Tuples<Integer, String>> tuples = Tuples.zip(
Tuple.of(Arrays.asList(1, 2), Arrays.asList("foo", "bar")
);
assertThat(tuples).containsExactly(
Tuple.of(1, "foo"), Tuple.of(2, "bar")
)This form of the method makes the purpose of unzip more obvious--it turns a Iterable/Stream/Array of Tuples into
a single Tuple containing a List of items.
Tuple<List<String>, List<Integer>> unzipped = Tuples.unzip(
Tuple.of("foo", 1),
Tuple.of("bar", 2),
Tuple.of("baz", 3)
);
assertThat(unzipped.getFirst()).containsExactly("foo", "bar", "baz");
assertThat(unzipped.getSecond()).containsExactly(1, 2, 3);