Skip to content

Strongly typed tuple library for java - immutable and mutable implementations

License

Notifications You must be signed in to change notification settings

solubris/typedtuples

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Build Status Quality Gate Status Maven Central Javadocs

TypedTuples

Strongly typed tuple library for java

Install

  • Maven
        <dependency>
          <groupId>com.solubris</groupId>
          <artifactId>typedtuples</artifactId>
          <version>2.1</version>
        </dependency>
  • Gradle
        implementation 'com.solubris:typedtuples:2.1'

Example

Multivalued Computation

Java streams don't handle computation of multiple values nicely, eg:

  • compute sum(N), sum(N^2)

This could be done using arrays as follows:

        int[] result = IntStream.rangeClosed(1, 3)
                .mapToObj(i -> new int[]{i, i * i})
                .reduce(
                        new int[2],
                        (l, r) -> new int[]{l[0] + r[0], l[1] + r[1]}
                );

With tuples and a tuple accumulator, this can be done as follows:

        CoupleAccumulator<Integer, Integer> accumulator = Accumulator.of(Integer::sum, Integer::sum);
        Couple<Integer, Integer> result = IntStream.rangeClosed(1, 3)
                .mapToObj(i -> ImmutableTuple.of(i, i * i))
                .reduce(
                        ImmutableTuple.of(0, 0),
                        accumulator::combine
                );

Enrichment

Enriching a stream of data can be done as follows:

        List<StringStats> result = Stream.of("abc", "1234", "zzz")
                .map(ImmutableTuple::of)
                .map(s -> s.mapAndAdd(String::length))
                .map(sl -> sl.mapFirstAndAdd(this::isPalindrome))
                .map(ImmutableTuple.to(StringStats::new))
                .collect(Collectors.toList());

Usage

There are 3 types of tuples which can be created from the builder classes as follows:

        ImmutableTuple.of(0, 0);
        MutableTuple.of(0, 0);
        Accumulator.of(Integer::sum, Integer::sum);

The api can the be explored from the results of these methods.

Strong typing

The tuples are never converted to the Object class.

Alternative tuple libraries have an Object[] toArray(); If this is the requirement, then its better to use a List<Object> directly. No need to complicate the solution with tuples.

Not Serializable

Tuples are only meant to be used as temporary holders for manipulation. So they should not be used as fields in other classes which means they don't need to be serializable.

Not Comparable

Without knowing if the types are comparable, then the tuples also can't be comparable (without casting).

However, some custom comparators are provided as follows:

        list.sort(Couple.compareByAllFieldsInOrder());
        list.sort(Couple.compareByAllFieldsInReverseOrder());
        list.sort(Single.compareByAllFieldsInOrder(String::length));
        list.sort(Single.compareByAllFieldsInOrder(Comparator.nullsLast(Integer::compareTo));

English names

No names like tuple2 because they are not fluent.

Stream friendly

Designed for use in streams where tuples are especially useful for manipulating the intermediate values. Methods like map are especially useful in stream operations.

Java 14 Record types

Will record types eliminate the need for tuples? Let's look at the example of returning a Couple of values.

        public Couple<String, String> getNameValue() {
            return ImmutableTuple.of("name", "value");
        }

How could this be done with record types?

        record NameValue(String name, String value){}
        public NameValue getNameValue() {
            return new NameValue("name", "value");
        }

So record types would still require the creation of a separate definition, however that definition would be very concise. This is probably suitable for method returns, but still not suitable for multistage stream enrichment as every stage would require a record definition. Other limitations:

  • it's not possible to have mutable record types
  • record types don't support generics
  • record types wont have the rich api of tuples

Record types can be a good target for the result of enrichment, eg:

        ImmutableTuple.of("name", "value").transform(NameValue::new);

Alternatives

Arity Naming self contained Immutable Mutable Strongly Typed Accumulators Comparators Collectors Overloaded Builders Primitives Nullable Values
TypeTuples 0 - 10 English ✔️ ✔️ ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
javatuples 1 - 10 English ✔️ ✔️ ✔️
jooq tuples 0 - 16 Numerical ✔️ ✔️ ✔️
apache lang3 2 - 3 English ✔️ ✔️ ✔️
eclipse collections 2 English ✔️ ✔️ ✔️
reactor utils 2 - 8 Numerical ✔️ ✔️
  • org.javatuples

In the Tuple base class it holds the values here:

private final Object[] valueArray;
private final List<Object> valueList;

This is in addition to the Pair class (for instance) values:

private final A val0;
private final B val1;

The valueList is populated with Arrays.asList(valueArray), so it doesn't copy all the values again. In summary, every value is stored twice and there are two extra references for each tuple. So for a Pair, that's 4 extra object references (or 200%).

  • org.eclipse.collections.impl.tuple.Tuples

  • reactor.util.function.Tuples

  • org.apache.commons.lang3.tuple

    • is comparable - uses reflection to work out which comparator
  • org.jooq.lambda.tuple

    • toArray(), Comparable, Serializable, Cloneable
    • concat, split, limit, skip, swap, map, mapAll
    • collect tuples from multiple collectors
    • not self contained

About

Strongly typed tuple library for java - immutable and mutable implementations

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •