package ch.claude_martin.lambda;
import java.lang.reflect.Constructor;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
/**
* A {@link Function} that returns a <code>null</code> of type Void.
*
* <p>
* This is to demonstrate why a {@link Consumer} isn\'t also a {@link Function}.
* <p>
* This interface could come handy if you need a collection of functional methods that are all of
* type {@link Function} but you want to include some {@link Consumer}s.
* <p>
* {@link UnaryOperator} is a Function as it has a return value, but a {@link Consumer} does not
* return anything. There exists a member {@link #VOID} that references an instance of {@link Void}
* or null and can be used as the returned value.
* <p>
* The same is true for similar Types such as Supplier. There you\'d have to pass something to
* {@link Supplier#get() get}.
*/
@FunctionalInterface
public interface ConsumerFunction<T> extends Function<T, Void> {
/**
* {@inheritDoc}
*
* @returns instance of {@link Void} or null
*/
public Void apply(T t);
/** @see Consumer#accept(Object) */
default public void accept(final T t) {
apply(t);
}
/** Convert this object to a regular {@link Consumer}. */
default public Consumer<T> toConsumer() {
return ConsumerFunction.this::apply;
}
/**
* This instance of {@link Void} can be used as the returned value. It is null if no instance
* could be created.
*/
public static final Void VOID = ((Supplier<Void>) () -> {
try {
final Constructor<Void> constructor = Void.class.getDeclaredConstructor();
constructor.setAccessible(true);
return constructor.newInstance();
} catch (Throwable t) {
return null;
}
}).get();
/** Convert some {@link Consumer} to a {@link Function}. */
public static <T> ConsumerFunction<T> toFunction(final Consumer<T> consumer) {
return t -> {
consumer.accept(t);
return VOID;
};
}
/** @see Consumer#andThen(Consumer) */
default ConsumerFunction<T> andThen(final ConsumerFunction<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> {
apply(t);
after.apply(t);
return VOID;
};
}
/** @see Consumer#andThen(Consumer) */
default Consumer<T> andThen(final Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> {
apply(t);
after.accept(t);
};
}
}