Created
November 10, 2017 16:21
-
-
Save benjiman/a8945f378691f4c1d258a12bed825ec2 to your computer and use it in GitHub Desktop.
Anonymous Types with Java 10
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.benjiweber.anontypes; | |
import java.util.*; | |
import java.util.function.Consumer; | |
import java.util.function.Function; | |
import java.util.function.Predicate; | |
import java.util.function.UnaryOperator; | |
import java.util.stream.Collectors; | |
import java.util.stream.Stream; | |
import static java.util.stream.Collectors.*; | |
public class Example { | |
public static void main(String... args) { | |
var x = (Quacks & Waddles) Mixin::create; | |
x.quack(); // prints Quacking | |
x.waddle(); // prints Waddling | |
var y = (IsA<List<String>> & Mappable<String> & FlatMappable<String> & Joinable<String>) | |
() -> List.of("Anonyous", "Types"); | |
System.out.println(y.join(",") + " - " + y.size()); // prints Anonymous,Types - 2 | |
System.out.println(y.map(i -> i+i)); // prints [AnonyousAnonyous, TypesTypes] | |
System.out.println(y.flatMap(i -> List.of(i.split("")))); // prints [A, n, o, n, y, o, u, s, T, y, p, e, s] | |
} | |
interface Mixin { | |
void __noop__(); | |
static void create() {} | |
} | |
interface Quacks extends Mixin { | |
default void quack() { | |
System.out.println("Quacking"); | |
} | |
} | |
interface Waddles extends Mixin { | |
default void waddle() { | |
System.out.println("Waddling"); | |
} | |
} | |
interface IsA<T> { | |
T delegate(); | |
} | |
interface Mappable<T> extends ForwardingList<T> { | |
default <R> List<R> map(Function<? super T, ? extends R> mapper) { | |
return delegate().stream().map(mapper).collect(toList()); | |
} | |
} | |
interface FlatMappable<T> extends ForwardingList<T> { | |
default <R> List<R> flatMap(Function<? super T, ? extends List<? extends R>> mapper) { | |
return delegate().stream().flatMap(i -> mapper.apply(i).stream()).collect(toList()); | |
} | |
} | |
interface Joinable<T extends CharSequence> extends ForwardingList<T> { | |
default String join(CharSequence delimiter) { | |
return delegate().stream().collect(Collectors.joining(delimiter)); | |
} | |
} | |
interface ForwardingList<T> extends List<T>, IsA<List<T>> { | |
List<T> delegate(); | |
default int size() { | |
return delegate().size(); | |
} | |
default boolean isEmpty() { | |
return delegate().isEmpty(); | |
} | |
default boolean contains(Object o) { | |
return delegate().contains(o); | |
} | |
default Iterator<T> iterator() { | |
return delegate().iterator(); | |
} | |
default Object[] toArray() { | |
return delegate().toArray(); | |
} | |
default <T1> T1[] toArray(T1[] a) { | |
return delegate().toArray(a); | |
} | |
default boolean add(T t) { | |
return delegate().add(t); | |
} | |
default boolean remove(Object o) { | |
return delegate().remove(o); | |
} | |
default boolean containsAll(Collection<?> c) { | |
return delegate().containsAll(c); | |
} | |
default boolean addAll(Collection<? extends T> c) { | |
return delegate().addAll(c); | |
} | |
default boolean addAll(int index, Collection<? extends T> c) { | |
return delegate().addAll(index, c); | |
} | |
default boolean removeAll(Collection<?> c) { | |
return delegate().removeAll(c); | |
} | |
default boolean retainAll(Collection<?> c) { | |
return delegate().retainAll(c); | |
} | |
default void replaceAll(UnaryOperator<T> operator) { | |
delegate().replaceAll(operator); | |
} | |
default void sort(Comparator<? super T> c) { | |
delegate().sort(c); | |
} | |
default void clear() { | |
delegate().clear(); | |
} | |
default T get(int index) { | |
return delegate().get(index); | |
} | |
default T set(int index, T element) { | |
return delegate().set(index, element); | |
} | |
default void add(int index, T element) { | |
delegate().add(index, element); | |
} | |
default T remove(int index) { | |
return delegate().remove(index); | |
} | |
default int indexOf(Object o) { | |
return delegate().indexOf(o); | |
} | |
default int lastIndexOf(Object o) { | |
return delegate().lastIndexOf(o); | |
} | |
default ListIterator<T> listIterator() { | |
return delegate().listIterator(); | |
} | |
default ListIterator<T> listIterator(int index) { | |
return delegate().listIterator(index); | |
} | |
default List<T> subList(int fromIndex, int toIndex) { | |
return delegate().subList(fromIndex, toIndex); | |
} | |
default Spliterator<T> spliterator() { | |
return delegate().spliterator(); | |
} | |
default boolean removeIf(Predicate<? super T> filter) { | |
return delegate().removeIf(filter); | |
} | |
default Stream<T> stream() { | |
return delegate().stream(); | |
} | |
default Stream<T> parallelStream() { | |
return delegate().parallelStream(); | |
} | |
default void forEach(Consumer<? super T> action) { | |
delegate().forEach(action); | |
} | |
} | |
} |
You're using this feature very creatively but it feels pretty hacky. I wouldn't recommend anyone to use this in real code (but perhaps you wouldn't either!). It was interesting to see though, it wouldn't have crossed my mind to try this kind of things!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It's cool that you can do something like this in Java 10. But I'm trying to understand how this is actually a mixin and how it is an improvement over e.g. creating a ForwardingList class and just adding the methods you want to that? Is there a way to add behavior to a class you don't have control over (like java List classes) without writing a forwarding method to re-implement the entire interface (as with ForwardingList here)?