Created
June 3, 2025 21:11
-
-
Save dexterous/543c4d66e1f4cc7dabdaf16a6b6c09bd to your computer and use it in GitHub Desktop.
Tap pattern in Java using Functional Interfaces
This file contains hidden or 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
import java.util.Collections; | |
import java.util.Objects; | |
import java.util.Set; | |
import java.util.stream.Collectors; | |
class Employee { | |
private Set<Org> orgs; | |
private Org primaryOrg; | |
public Org getPrimaryOrg() { return primaryOrg; } | |
public void setOrgs(final Set<Org> orgs) { | |
this.orgs = orgs; | |
if (!orgs.isEmpty()) { | |
this.primaryOrg = Collections.max(orgs); | |
} | |
} | |
public String toString() { | |
return String.format( | |
"Employee[%s]", | |
orgs.parallelStream(). | |
map(o -> String.format("%s%s", o.equals(primaryOrg) ? "^" : "", o) ). | |
collect(Collectors.joining(", ")) | |
); | |
} | |
public int hashCode() { return Objects.hash(orgs, primaryOrg); } | |
public boolean equals(final Object other) { | |
return other != null && | |
other.getClass() == Employee.class && | |
(this == other || this.equals((Employee) other)); | |
} | |
private boolean equals(final Employee other) { | |
return other != null && | |
(this == other || | |
(this.orgs.equals(other.orgs) && | |
this.primaryOrg.equals(other.primaryOrg))); | |
} | |
} |
This file contains hidden or 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
import java.util.Set; | |
import java.util.function.Consumer; | |
import java.util.function.Function; | |
import java.util.function.Supplier; | |
import java.util.function.UnaryOperator; | |
import java.util.stream.Stream; | |
import java.util.Objects; | |
class Main { | |
public static void main(String[] args) { | |
System.console().printf("%n"); | |
System.console().printf( | |
"%s%n", | |
Tap.sNew(Employee.class).with(e -> { | |
Tap<Org> newOrg = Tap.sNew(Org.class); | |
e.setOrgs(Set.of( | |
newOrg.with(o -> o.setCode("Thoughtworks")), | |
newOrg.with(o -> o.setCode("Grainger")) | |
)); | |
}) | |
); | |
System.console().printf("%n"); | |
UnaryOperator<Integer> doubler = (Integer n) -> n * 2; | |
// wrap tap in a static method to void having to invoke apply(...) | |
System.console().printf("%d%n", | |
printap("Result").apply( | |
doubler. | |
compose(printap("Before")). | |
andThen(printap("After" )). | |
apply(10) | |
) | |
); | |
System.console().printf( | |
"%s%n", Objects.toString(Tap.s(new Org()).with(o -> o.setCode("Foo")))); | |
} | |
// XXX: Not generified as format string assumes object is decimal | |
private static UnaryOperator<Integer> printap(String message) { | |
return Tap.ped((Integer n) -> System.console().printf("%6s... %d%n", message, n)); | |
} | |
} |
This file contains hidden or 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
class Org implements Comparable<Org> { | |
private String code; | |
public void setCode(String code) { this.code = code; } | |
public int compareTo(Org other) { | |
return this.code.compareTo(other.code); | |
} | |
public String toString() { return String.format("Org[code=%s]", code); } | |
public int hashCode() { return code.hashCode(); } | |
public boolean equals(final Object other) { | |
return other != null && | |
other.getClass() == Org.class && | |
(this == other || this.equals((Org) other)); | |
} | |
private boolean equals(final Org other) { | |
return other != null && | |
(this == other || this.code.equals(other.code)); | |
} | |
} |
This file contains hidden or 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
import java.lang.reflect.Constructor; | |
import java.util.Optional; | |
import java.util.concurrent.Callable; | |
import java.util.function.Consumer; | |
import java.util.function.Function; | |
import java.util.function.Supplier; | |
import java.util.function.UnaryOperator; | |
// XXX: Does Tap inherit @FunctionalInterface from Supplier? | |
// XXX: Does it make sense for a Tap to be a Callable? | |
public interface Tap<T> extends Supplier<T>, Callable<T> { | |
public static <T> Tap<T> ping(final T object) { | |
return s(object); | |
} | |
public static <T> Tap<T> s(final T object) { | |
return () -> object; | |
} | |
public static <T> Tap<T> sNew(final Class<T> clazz) { | |
// XXX: Well, this sucks balls. | |
Constructor<T> ctor; | |
try { | |
ctor = clazz.getDeclaredConstructor(); | |
} catch (NoSuchMethodException x) { | |
throw new IllegalArgumentException( | |
String.format("{} has does not have a no-arg constructor.", clazz), x); | |
} | |
return ctor::newInstance; | |
/* | |
//TODO: Consider supporting ctor args | |
return () -> { | |
try { | |
return clazz.getDeclaredConstructor().newInstance(); | |
} catch (final Exception x) { | |
// TODO: Do better handing of x; What _could_ we even do here? | |
return null; | |
} | |
}; | |
*/ | |
} | |
public static <T> UnaryOperator<T> ped(final Consumer<? super T> tapper) { | |
return (final T target) -> Tap.s(target).with(tapper); | |
} | |
public default T get() { | |
try { | |
return this.call(); | |
} catch (final Exception x) { | |
// TODO: Do better handing of x; What _could_ we even do here? | |
return null; | |
} | |
} | |
// TODO: consider if we should return Optional<T> | |
// XXX: we shouldn't; we support tapping nulls | |
public default T with(final Consumer<? super T> tapper) { | |
final T target = this.get(); | |
Optional.ofNullable(target).ifPresent(tapper); | |
return target; | |
} | |
// XXX: original implementation of a bare basic tap function | |
// Source: https://dzone.com/articles/tap-that-assignment-with-java | |
public static <T> T tap(T object, Consumer<T> consumer) { | |
consumer.accept(object); | |
return object; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment