Enhance Map, List, and Set such that these interfaces extend Function, IntFunction, and Predicate, respectively

Ralf Spöth ralf.spoeth at gmail.com
Thu Sep 15 15:19:35 UTC 2022


Dear all,

I just stumbled about some frequent uses of collections as filters and mapping functions, and I am wondering whether it's possible to enhance the core collection interfaces Map, List, and Set:

(please forgive lousy syntax hereinafter)

interface Map<K, V> extends Function<K, V> {
    default V apply(K k) {return get(k);}
}

interface List<T> extends IntFunction<T> {
   default T apply(int index) { return get(I);}
}

interface Set<T> extends Predicate<T> {
   default boolean test(T t) {return contains(t);}
}

The cost of extending existing interfaces in widespread use may be prohibitive, plus you may find the value proposition not very convincing.

The interpretation of a Map as a Function feels very natural, although the use of the given map in a stream is also straightforward:

Stream.of(1, 2).map(Map.of(1, "One", 2, "Two")::get).toList(); // ["One", "Two"]

Assigning the map to a function variable is a little more demanding:

// var m = Map.of(...)::get; compiler error
Function<Integer, String> m = Map.of(1, "One")::get; // WORKS

Since we enjoy the pleasures of local variable type inference, this is a little awkward.

If a map were a function, then we might write instead:

var m = Map.of(1, "One", 2, "Two");
Stream.of(1, 2).map(m).toList(); // ["One", "Two"]

The interpretation of a list as a function of an index may seem a little more far-fetched:

var l = List.of("One", "Two", "Three");
IntStream.range(0, l.size()).filter(i -> i%2==0).mapToObj(l::get).toList(); // ["One", "Three"];

The test for inclusion in a set is a common operation and is therefore a frequent candidate for filters in stream operations.

var primes = Set.of(2, 3, 5, 7);
IntStream.range(5, 10).filter(primes::contains).toArray(); // [5, 7]

With Set implementing Predicate and List implementing IntFunction we may write:

var primes = Set.of(2, 3, 5, 7);
var elems = List.of("One", "Two", "Three", "Four");
IntStream.range(0, 5).filter(primes).mapToObj(elems).toList(); // ["Three", "Four"]

Arguably, 

IntStream.range(0, 5).filter(primes::contains).mapToObj(elems::get).toList();

is not too bad as well…

Just an idea...

Thanks for reading!
- Ralf
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/java-se-spec-comments/attachments/20220915/ebdaa596/attachment.htm>


More information about the java-se-spec-comments mailing list