
Why There Is Interface Pollution in Java 8 - Jarlakxen
http://blog.informatech.cr/2014/04/04/jdk-8-interface-pollution/
======
steve_barham
Regarding the 'checked exception issue'; an alternative technique to the
method-wrapping-lambda is to use a default interface method to implement the
non-exceptional interface, which delegates to the possibly-exceptional method.
It's a bit fussy, but it's a nice technique to know:

    
    
        interface IOConsumer<T> extends Consumer<T> {
            @Override
            default void accept(T t) {
                try { 
                    maybeAccept(t); 
                } catch (IOException ie) { 
                    throw new RuntimeException(ie); }
                }
    
            void maybeAccept(T t) throws IOException;
        }
    

As IOConsumer<T> is also a Consumer<T>, if you can assign the lambda to an
IOConsumer<T> it will get this wrapping behaviour automatically. So your code
might look something like:

    
    
            try (Writer writer = new StringWriter()) {
                final IOConsumer<String> ioPrinter = writer::write;
    
                // hand ioPrinter off to something that expects a Consumer<String>
            }
    

This is by no means beautiful; for 'writer::write' to be treated as an
IOConsumer<T> requires that the target type be IOConsumer<T>, so typically
would require an interim assignment. It does allow us to simplify the
'wrapping' method, though, so that lambdas can again be used as one-liners:

    
    
        static <T> Consumer<T> maybe(IOConsumer<T> consumer) {
            return consumer;
        }
    
        try (Writer writer = new StringWriter()) {
            final Consumer<String> printer = maybe(writer::write);
        }
    

It would be nice not to have these wrinkles, but I think Java 8 has done a
fairly decent job of preserving backwards compatibility while introducing
language features and APIs which feel like a vast improvement. I'd love to see
reified generics in the future, particularly if the type parameter can be
extended to support primitives.

~~~
BrandonM
We currently use the following pattern:

    
    
        interface ConsumerE<T, E extends Exception> {
            void accept(T t) throws E;
        }
    

This actually works! The type inference is good enough to figure out the
actual type of E.

Note that Java 8 also includes specialized wrappers like RuntimeIOException.
So it might be nice to extend your example:

    
    
        static <T, E extends Exception> Consumer<T> wrapped(
                Function<? super E, RuntimeException> wrapper,
                ConsumerE<T, E> consumer) {
            return (t) -> {
                try {
                    consumer.accept(t);
                } catch (RuntimeException e) {
                    throw e;
                } catch (Exception e) {
                    throw wrapper.apply((E) e);
                }
            };
        }
    

Used as follows:

    
    
        Consumer<String> printer = wrapped(RuntimeIOException::new, writer::write);

~~~
phernandez
I was trying to work around this problem also and found this library:
[https://github.com/jOOQ/jOOL](https://github.com/jOOQ/jOOL), from the guys at
Jooq. They did all the hard work to wrap all the FunctionalInterfaces in
unchecked exceptions. Hope this helps.

~~~
BrandonM
Thanks a lot for the pointer! That's most of what we need.

------
lmm
All this makes me very happy I nowadays work almost exclusively in Scala. No
language is perfect, but Scala supports all the things Java 8 does (a few
things are experimental until the next release), has straightforward FunctionN
interfaces (as the article mentions) in addition to SAM synthesis (I mean, why
not just do both?), and while a recent emphasis on compatibility means it's
starting to accumulate its own cruft, it at least drops the first ~10 years of
Java's backwards-compatibility awkwardness.

~~~
pron
And it makes me happy for ditching Scala in favor of Java some years ago after
realizing that if you're writing a 2MLOC software that your organization is
going to depend on for the next decade, backwards compatibility is so much
more important than any language feature (even if that feature is an extremely
clever type system that extremely clever developers who like that sort of
thing can use to statically prove that their function's argument is always
prime).

~~~
jeremyjh
You do realize that the compatibility issues are binary compatibility, not
source compatibility right? It does seem to be the case that many Java project
groups are not setup to build their dependencies from source, but for such a
large code-base I think building dependencies from source and hosting your own
binary repository is probably not a bad idea.

~~~
pron
It's (almost) just as bad when you try to manage lots of dependencies.

> but for such a large code-base I think building dependencies from source ...
> is probably not a bad idea.

That's a bad idea. You want to manage as little code as possible, especially
given the already large codebase. It's certainly doable, but in the end you
realize the benefit is just not worth the effort.

Of course, that was just a symptom of a far larger problem: It always seemed
that when faced with the dilemma of favoring some PL research goal vs. real
working-man's use, Scala always chose the former; it was like its real (though
not stated) target audience were PL PhDs. It seems the winds have shifted
recently, but probably too late, and Scala is already weighed down by too many
"PhD" features that need to be removed in a way that would _severely_ break
source compatibility.

Say what you want about Java, it's really great for big projects you must
depend on and need to maintain for many years.

~~~
rtpg
>It's certainly doable, but in the end you realize the benefit is just not
worth the effort.

The benefit of using a language that, at _worst_, is as productive as Java,
and at best miles better?

>faced with the dilemma of favoring some PL research goal vs. real working-
man's use, Scala always chose the first

Scala is pretty straightforward in terms of features, classifying it as "PL
research" is a bit much.

>Say what you want about Java, it's really great for big projects you must
depend on and need to maintain for many years.

My experience has been that larger projects end up accumulating so much
boilerplate that it becomes extremely hard to manage (I fear that Scala's
standard library is becoming like this too, but third-party libs seem to avoid
this).

I have trouble finding any non-deployment-related argument against Scala in
the Scala vs. Java comparison.

~~~
justinpombrio
> Scala is pretty straightforward in terms of features, classifying it as "PL
> research" is a bit much.

False.

[http://www.scala-lang.org/old/node/143.html#papers](http://www.scala-
lang.org/old/node/143.html#papers)

~~~
frowaway001
[http://citeseerx.ist.psu.edu/search?q=java&submit=Search&sor...](http://citeseerx.ist.psu.edu/search?q=java&submit=Search&sort=rlv&t=doc)

    
    
        Results 1 - 10 of 119,620
    

What's your point again?

~~~
justinpombrio
Ah, the difference is that much of the research done on Scala makes it into
the language

~~~
frowaway001
Like what? Generics?

------
AndrewDucker
I'm glad that, whether by better design, or lucky happenstance, C# managed to
avoid bumping into these issues.

(It still has the problems, of course, that WinForms was written back in 2002
and doesn't even use Generics, which would make the API a lot cleaner.)

~~~
_delirium
To a large extent C# is basically Java 2.0, what you might build if you were
starting a broadly similar language/runtime project after watching a few years
of the first one (the initial release was about 5 years later, 2000 vs. 1995).
The language is pretty nice imo, and I'd choose it over Java. But the runtime
situation is somewhat worse if you need cross-platform support— the JVM is
better than Mono overall. So I'd pick C# over Java iff you can use the
official Microsoft runtime, i.e. you don't need cross-platform or open-source.

~~~
edwinnathaniel
Unfortunately JVM is better than CLR in terms of feature set and performance.

~~~
pjmlp
Only when you forget about:

\- tail call optimization

\- AOT compilation as part of the standard toolchain. No need to rely on third
party vendors

\- value types

\- reifeid generics

\- painless FFI with external code

EDIT: - Forgot about direct control over SIMD instructions.

All of those issues are being discussed for Java 9+ and have corresponding
projects at OpenJDK.

~~~
CmonDev
Also two very well supported versions of VM with distinct advantages:

1) Mono - deploy to every major mobile platform using a well-defined single-
vendor pipeline.

2) .NET - unmatched performance on Windows.

~~~
edwinnathaniel
There are different JVM implementations too y'know :)

[http://www.azulsystems.com/](http://www.azulsystems.com/)

------
EdwardDiego
Can someone please define for me what exactly 'interface pollution' is and why
it's so bad?

Because I read this article, and the article from the Jooq blog he references,
and I can't see anything beyond one guy's preference for one thing, and Java 8
does it the other way.

~~~
Sharlin
Surely you can see the problem with the combinatorial explosion in the number
of interfaces required?

~~~
EdwardDiego
We already have this 'explosion' in Java-land. What's the difference between
interfaces implemented as a lambda and... interfaces with a single method
implemented as an inline anonymous class? Which is effectively what these
'lambdas' are syntactic sugar for. It's still an improvement for Java the
language.

------
lnanek2
C# got rid of type erasure and is better for it. Java really needs to bite the
bullet and do the same. It is just a compatibility hack anyway.

~~~
alkonaut
I have tried to make that point but usually I'm told it's impossible ir
unnecessary.

a compromise would perhaps be to allow at least reified primitive generics so
that List<int> would be a proper runtime type whereas List<Object> would be
the runtime version of all reference types in List<T>.

Obviously, this would be a half-assed solution unless custom value types like
point structs would also be allowed without boxing in similar scenarios. I'm
not sure but I think that these things need pretty significant changes to the
runtime.

My conclusion is that Java doesn't need this. It won't be elegant no matter
what amount of lipstick is added. I even think some of the current features
like lambdas are overkill. Instead, features should be added at the vm level
to allow for other jvm langs to use them. A good functional language with good
generics over primitives and proper value types would be awesome. F# is a good
example of such a language (scala and clojure aren't)

~~~
pron
The work is already underway in Project Valhalla:
[http://openjdk.java.net/projects/valhalla/](http://openjdk.java.net/projects/valhalla/)

Once it's been decided Java should get value types, generic reification became
a more urgent necessity.

~~~
alkonaut
Interesting. Curious to see if they choose exactly the same approach to e.g.
value types as the CLR and C# teams did. In C# it feels like there are very
few places where choices could have been made differently.

Something I really miss in C#/Java is a possibility to opt out of GC and use
more stack allocation.

~~~
pron
Java's value types will be immutable, while in C# I believe structs are
mutable. This is a very important difference with serious implications to
concurrency.

> Something I really miss in C#/Java is a possibility to opt out of GC and use
> more stack allocation.

The tradeoffs are often not what you think they are.

~~~
alkonaut
Mutable structs in c# are rare, rarely useful and often dangerous, but in some
perf critical scenarios that hack is needed. Most notably the standard
List<T>.Enumerator is a mutable struct because othrrwise an object would have
to be created on the heap for the sole purpose of iterating a list.

Not sure whether this was actually one of the reasons for allowing mutable
structs to begin with, the use case is critical enough that it might well have
been.

