Java 8 doesn’t have implicits (for which much thanks will be given in some quarters), which makes it difficult to create typeclasses in a Scala(z)ish fashion. This is one possible compromise.

public class MonoidTest { public interface Monoid<T> { public static <T> Function<Monoid<T>, Optional<T>> sum(Collection<T> items) { return monoid -> { Iterator<T> iter = items.iterator(); if (!iter.hasNext()) { return Optional.empty(); } T accumulator = iter.next(); while (iter.hasNext()) { accumulator = monoid.append(accumulator, iter.next()); } return Optional.of(accumulator); }; } T append(T first, T second); } public interface IntegerMonoid { static <R> R run(Function<Monoid<Integer>, R> f) { return f.apply((a, b) -> a + b); } } public interface StringMonoid { static <R> R run(Function<Monoid<String>, R> f) { return f.apply((a, b) -> a + b); } } @Test public void sums() { Optional<Integer> sumOfInts = IntegerMonoid.run(Monoid.sum(Arrays.asList(1, 2, 3))); Optional<String> sumOfStrings = StringMonoid.run(Monoid.sum(Arrays.asList("a", "b", "c"))); assertThat(sumOfInts.get(), equalTo(6)); assertThat(sumOfStrings.get(), equalTo("abc")); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public class MonoidTest { public interface Monoid <T> { public static <T> Function < Monoid <T> , Optional <T> > sum ( Collection <T> items ) { return monoid -> { Iterator <T> iter = items . iterator ( ) ; if ( ! iter . hasNext ( ) ) { return Optional . empty ( ) ; } T accumulator = iter . next ( ) ; while ( iter . hasNext ( ) ) { accumulator = monoid . append ( accumulator , iter . next ( ) ) ; } return Optional . of ( accumulator ) ; } ; } T append ( T first , T second ) ; } public interface IntegerMonoid { static <R> R run ( Function < Monoid <Integer> , R > f ) { return f . apply ( ( a , b ) -> a + b ) ; } } public interface StringMonoid { static <R> R run ( Function < Monoid <String> , R > f ) { return f . apply ( ( a , b ) -> a + b ) ; } } @Test public void sums ( ) { Optional <Integer> sumOfInts = IntegerMonoid . run ( Monoid . sum ( Arrays . asList ( 1 , 2 , 3 ) ) ) ; Optional <String> sumOfStrings = StringMonoid . run ( Monoid . sum ( Arrays . asList ( "a" , "b" , "c" ) ) ) ; assertThat ( sumOfInts . get ( ) , equalTo ( 6 ) ) ; assertThat ( sumOfStrings . get ( ) , equalTo ( "abc" ) ) ; } }