
Modern Java – A Guide to Java 8 - aronhunt470
https://github.com/winterbe/java8-tutorial
======
mabbo
My Java code has improve dramatically since I started (ab)using Optionals.

    
    
      String foo = Optional.ofNullable(paramater)
                           .filter(...)
                           .map(a -> ...)
                           .map(b -> ...)
                           .orElseGet(() -> ...)
                           .orElse(defaultValue)
    

Between this kind of thing, and similar playing with Streams, some of the
ugliest code I work with is suddenly quite clear, coherent, understandable.

~~~
grokys
I'm not so up on Java, could someone explain why they chose "->" for lambdas
instead of the "=>" that C# and ES6 use, as those languages seem to me like
they would be the first place to look for inspiration.

~~~
kodablah
In addition to the other answers, I bet it's easier for a CFG to parse knowing
that "->" can't also be "negate and greater than" (since negation is only a
prefix op) whereas "=>" can easily be a fat arrow or greater-than-or-equal.

~~~
serge2k
Why would that be any harder? The tokens are different.

~~~
kodablah
True, Java does not support => as an alternative for >= so the ambiguity does
not exist. It was just a guess, but since it was probably not right, I decided
to dig. This mail post[1] explains that the extra equals sign becomes a bit
annoying w/ other equal signs in the same expression.

1 - [http://mail.openjdk.java.net/pipermail/lambda-
dev/2011-Septe...](http://mail.openjdk.java.net/pipermail/lambda-
dev/2011-September/004021.html)

------
kriro
I've always had some sort of mistrust of Java (neo-Cobol ohnoes!) but I'm
liking it more and more. Mostly I've come around to the fact that static
typing isn't as bad as my young self thought (and can in fact be quite cool).
The verbosity and "enterprisy" and committee oriented feel are still a bit off
putting but I've made a commitment to try some Java on a couple of weekends.
Did a bit of research and there's actually nice looking lean web-stuff, too
(Spark Framework, Ratpack). Played with the J8 features back when it was
released and they are pretty cool.

Cliffnotes: I think I have discriminated against Java mostly on a "religious"
basis. I think it's a great time for people like me to give it another shot
(especially if you have grown accustomed to functional ideas form other
languages in the meantime).

The repo is an excellent resource, bookmarked.

~~~
pjmlp
Good luck with your experiments.

Many of us in the 90's jumped into Java, in spite of its issues, because it
made it more pleasing to write cross platform code, than using C or C++ with
CORBA/COM across OSes with compilers that were still playing catchup with the
standards.

~~~
haxeny1
I never understood the following : Eiffel had a better syntax, better support
for core issues, Void type, design by contract, multiple-inheritance and an
intermediate virtual machine for portability although the most common target
was C code. To name a few. I was using Eiffel in a small side project just
about when Java released their 1.1.4 (a version before the object
serialization library, iirc). It was a sticking point for me. Add to that, to
program in java before IBM Visual Age was released was to using
vi/notepad(++?) editors. Coming from Smalltalk env that was a bit of a shock.
Eiffel commercial IDE from ISE was way better and its clever use of pick event
on the mouse's right click to drop to compile/run targets was actually easier
on my fingers, which is a side show, but good quality products demonstrate
quality at unexpected places.

I am still programming in java in my day job, knowing fully well that Java was
not my top five language choices. Eiffel's type system was a bit more advanced
than Java even way back in those days, so not only was I stuck without an ide
till VA for Java showed up or VisuallJ++ I also had to accept weak inheritance
and design by contract models. Performance of course was not even close to an
Eiffel compiled C code, which was probably addressed in later versions of
java.

My point being, that just as Eiffel was something that was better and set
aside by a few leading development shops, there must have been other languages
that could/should have received a fair share in language evaluation by
programmers, I dont necessarily mean limiting to Ruby, Python for example,
despite them being excellent tools, they may fall short in an enterprise
ecosystem. What happened at least I seem to think instead is a sort of
groupthink to start coding in Java because of rubbernecking. All in all, I
think that things could have been better if people paused to understand the
Java language model and fixed in java 1.2/3, or some earlier version so we
didnt have to wait till Java 1.8 to get these features. /rant.

~~~
rcurry
I developed a great interest in Eiffel after I read Bertrand Meyer's book
"Object Oriented Software Construction" (which I still think is one of the all
time great books on object-oriented programming), but I never found anyone
else that was using it and the IDE was way too expensive for me at the time.
It just seemed to me like one of those technologies you'd probably get to have
fun with on some niche project at a defense contractor, but that you'd
probably never see out in the more general software development world.

~~~
haxeny1
I was one of those folks who actually bought the personal license. Over years,
SmallEiffel came along and improved the ecosystem. Of course, now Eiffel has a
community/enterprise model. In any event, I do think that they were pricing
them out of the market. Defense contractors, seem to like ada more. The
feature that I miss from Eiffel is the Expanded (allocated on stack feature).
Even haskell has some #untyped to deal with boxing primitives. I thought that
Expanded was a stroke of genius: bringing specification to implementation
without the middleman(aka heap).

------
struppi
This is a really nice overview of the new Java 8 features. I like how this
tutorial communicates mostly with code snippets and has "read more" links for
most topics.

If you are using Java and have not tried Lambda Expressions, method references
and default methods, do so now! After that, you'll think "How was I able to
live without that?".

I also think that the way Java integrates lambda expressions (via functional
interfaces) is really nice. Sure, you have to write some boilerplate code in
some scenarios. But since they re-used interfaces and did not event some
"function" type (or similar), it fits really nicely into the existing
language.

If you don't know Java, this tutorial will probably not be enough - But that
probably wasn't the intentian anyway. It's a great intro to what has changed
with Java 8 (and all those changes are real improvements for the Java
language, IMHO).

~~~
rifung
_If you are using Java and have not tried Lambda Expressions, method
references and default methods, do so now! After that, you 'll think "How was
I able to live without that?"_

I think instead of "How was I able to live without that?", people are more
likely to exclaim "about time!"

~~~
struppi
Well... depends on who you ask. I, personally, was more in the "about time!"
camp. But I have met several programmers who didn't think they'd need those
"newfangled features" at first. Especially in the "early days" of Java 8...
And sometimes I still meet people like that. So that scentence was targeting
those developers that are still stuck with Java 5 or 6 or 7 and have never
tried Java 8.

Also, I was once co-teaching a C# workshop where we showed people how to work
with LINQ and extension methods (long, long time ago ;) ). Some participants
asked us if there was a way to configure the compiler to _forbid_ those
features for their team.

Not everybody likes "modern" features, I guess ;)

~~~
Cthulhu_
Well technically they didn't need them, no - I've been working with for and
for-in loops for years before learning other languages (like Scala, JS) that
had a .map function that could do the same thing but much more compact and
expressive. So their argument isn't wholly invalid, and TBF I'd rather see a
regular for-in loop than my colleague's atrocious 200-character oneliners.

------
mhaymo
> maps don't support streams

This is very misleading. There is not a #stream method on Map because Map
supports three different streams:

    
    
        map.keySet().stream()
        map.values().stream()
        map.entrySet().stream()

~~~
tokenizerrr
But those are streams on sets.

~~~
mhaymo
Those are streams on views on the map. My complaint is that a reader seeing
"maps don't support streams" with no further explanation is unlikely to get
the correct idea, and may infer that something like

    
    
      map.entrySet().stream().filter(e -> e.getKey().equals(e.getValue())).findAny()
    

is not expressible.

------
mark_l_watson
This is a really nice write up!

Java 8 is such a huge improvement over previous versions. One thing it still
lacks is a better literal format for defining maps, etc.

I just self published a book that uses Java 8
([https://leanpub.com/powerjava](https://leanpub.com/powerjava) if you will
pardon a plug) and to be honest I got some pushback from a few people who like
my books as to why I didn't use Clojure, Haskell, etc. To be honest I do
prefer Clojure and Haskell, but the Java ecosystem is so huge, with so many
good libraries that sometimes it is the more practical language to use.

~~~
mavelikara
Mark, I am sure you know this, but I am posting this for the benefit of others
who might not.

For literal maps, I tend to use double brace initialization style. It is more
verbose than languages with direct literal support for maps and creates an
extra anonymous class, but it keeps the map in a single syntactic construct.
For lists, I use Arrays.asList(a,b,c) style; if you static import the method
it reads nicely as-list-a-b-c.

~~~
pjmlp
Which is a no-go in Android as it can prevent GC in some cases, because as
anonymous inner class it holds a reference to its parent and you end up
leaking Activities.

It is usually presented as anti-pattern in talks about Android performance.

~~~
mavelikara
Ah, I have never programed for Android devices. Thanks for pointing this out.

------
escherize
I personally jumped right into Clojure on the jvm without much Java
experience. I've found it to be awesome. Is there a non-political reason that
someone should choose Java over Clojure (or possibly Scala)? Where does Java
shine?

~~~
lmm
All IME, and as a Scala fan:

Clojure has a weakly integrated type system (an inherent disadvantage of
optional type systems). At the simplest level this makes silly errors much
easier and means you have to write more tests to maintain the same defect
rate.

The lack of types mean you require extensive use of macros for advanced
functionality. IME macros have major maintainability issues in a multi-person
codebase.

Both these things are major disadvantages for automatic comprehensibility of
code. Autocompletion can be more-or-less usable but will never be as good as
in Java or Scala. Automated refactoring is inherently unsafe in the presence
of macros (Scala's fancier typed constructs (typeclasses, for/yield with
custom types) mean you need macros much less often; Java tends to force you to
expand these things out by hand (or else use annotations which act as de facto
macros), which has its own maintainability issues but does at least mean
automated refactoring will work correctly).

Some of the language culture pushes people towards less principled
abstractions. From this side of the fence that looks like anti-
intellectualism; no doubt from their side it's pretension on typed
programmers' part. But either way I think they're setting themselves up for
long-term maintainability issues (e.g. the semantics of clojure transducers in
the presence of errors are infuriatingly not-quite-right, which will either
remain a painful gotcha forever, or necessitate a painful migration in the
future).

As a minority language Clojure may not be as well supported in the surrounding
ecosystem - partly things like IDEs but also code coverage tools, profilers,
monitoring.... Remember the JVM ecosystem is wider than just the languages
themselves.

There are good things about Clojure, but it's by no means clear-cut.

~~~
ubertaco
> IME macros have major maintainability issues in a multi-person codebase.

I have heard this a bunch, and I believe it, but I've never personally had an
opportunity to use a language that supports macros for a multi-person
codebase. I'd be interested to learn what are some of the pitfalls you've
seen, if you don't mind sharing.

~~~
lmm
It's not like I have a lot of experience (macros are much rarer in my primary
language, Scala). But it's usually just someone doing a refactor that "makes
sense" according to the logic of the regular language but not within the
macro. A lot of it is simple, "silly" things like trying to extract a repeated
piece of logic into a method call, only it doesn't work because the logic uses
something the macro hooks into, or just is transformed in a surprising way by
the macro that makes the reasoning incorrect. To take a completely trivial
real-world example, renaming a field is usually a safe operation that you can
do automatically (with an IDE) without even testing, but if that field's used
in a macro then maybe it represents a key in a JSON object and you've just
broken your web API. You notice it pretty quickly, and it's a two-minute fix -
but these kind of "thousand cuts" scenarios really slow development. Outright
production failures are less common but I've seen those when test coverage was
poor or other failures interacted.

------
mkobit
It wasn't touched on in this document, but I think more people should hear
about Nashorn. It is the new JavaScript Engine that, I believe, supports ES
5.1. It allows you to do some pretty neat things with Java/JavaScript
interacting in the same VM. Java 9 is planning on supporting ES6 <source
needed>.

You can see an introduction on this Oracle documentation:
[https://docs.oracle.com/javase/8/docs/technotes/guides/scrip...](https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/nashorn/api.html)

------
ctstover
I am the only one that has been thinking for months now that "modern" is the
most over used, pointless, and almost negatively connotative word in this
industry? Thought exercise: Imagine the ugliest flat and incomprehensible UI
widget you have seen lately, the most bloated website load that doesn't crash
the browser, and some mindless office dialog about "rising cloud costs". Now
pick one word. Survey says - you guessed it. So most certainly, if you need to
be more "modern", I'm sure java 8 is a vehicle to take you there.

------
amyjess
My company switched from 7 to 8 recently, and being able to use streams has
been a colossal productivity boost.

I'm actually in the process of putting together a presentation on how to work
magic with streams (because I'm one of the few people here who actually knows
how to use them), and this will probably get a mention in a "further reading"
slide, because it's really well written.

It's also inspired me to make a few slides focusing on the changes to Map and
Comparator, which I wasn't aware of until now.

------
hoffcoder
A really nice tutorial.

I have been writing Java code since 6 years. Although I can't say that I have
programmed in many other languages (I have coded in C/C++ and Javascript),
Java has been always very comfortable to use. It's easy to think of a solution
in the Object Oriented paradigm, and I think refactoring (when a requirement
changes) has not been much of a problem for me. It's only bad designs that
make the code more verbose than it should be, and I think verbosity is
actually a good way to articulate your thoughts, and see them evolve in front
of you. Recently when I started learning Haskell a bit, I found that there are
much faster and concise ways of writing code, but I still prefer Java because
of the clarity of the way it allows me to express my logic. People would say
that writing a line of code in Haskell would do what 10 lines of code in Java
would do, but in the long run, I have found that expressing programming
paraphernalia like interfaces and classes actually helps the coder in his job
(not necessarily results in wastage of time).

------
stephen
For people getting into Java 8, jOOL is a great, small library with a "Seq"
class that fills in the gaps missing in j.u.stream.Stream:

[https://github.com/jOOQ/jOOL](https://github.com/jOOQ/jOOL)

E.g. if you're coming from groovy/Scala and wonder "why doesn't Stream have
this method?", Seq probably either already has it, or the maintainer will be
open to adding it for you.

So, use jOOL. It's great.

That said, I still cringe that we have to do "someCollection.stream()..." (or
use fill-ins like jOOL) at all, because these methods aren't on j.u.List/etc.
itself...

My naive impression is that the JDK designers fixated on making streams
support parallelization (because fancy!), and so made some compromises on the
API, when in reality 98% of collections are small/not parallel, and I assert a
non-parallel, more complete API (e.g. more default methods directly on
j.u.List/j.u.Iterable themselves) would have been a net-win to most
programmers.

And the parallelized version could be a separate library/jar/something.

~~~
mkobit
That library has some fun/interesting generics declarations like this one
([https://github.com/jOOQ/jOOL/blob/master/src/main/java/org/j...](https://github.com/jOOQ/jOOL/blob/master/src/main/java/org/jooq/lambda/Seq.java#L4301-L4303))

> static <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
> T16> Seq<Tuple16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
> T14, T15, T16>> crossJoin(...

~~~
masklinn
Pretty much all languages with generics will have that kind of declarations,
the only question is how many type parameters they'll go up to. In C# Action
goes up to 16[0] while Rust's tuple go to 12[1] and GHC goes to 62[2]
(intending 100, but a comment notes declaration of a 63-wide tuple constructor
segfaults)

[0] [https://msdn.microsoft.com/en-
us/library/dd402872(v=vs.110)....](https://msdn.microsoft.com/en-
us/library/dd402872\(v=vs.110\).aspx)

[1] [https://github.com/rust-
lang/rust/blob/master/src/libcore/tu...](https://github.com/rust-
lang/rust/blob/master/src/libcore/tuple.rs#L238)

[2]
[https://downloads.haskell.org/~ghc/7.2.2/docs/html/libraries...](https://downloads.haskell.org/~ghc/7.2.2/docs/html/libraries/ghc-
prim-0.2.0.0/src/GHC-Tuple.html)

~~~
pjmlp
Yes, the only way to avoid this is to do as C++ and D, accept variable number
of types in the generics.

~~~
masklinn
That's an option, but it requires a significantly more complex generics
runtime.

------
ifdefdebug
interfaces with default implementations? Doesn't this look like... multiple
inheritance?

~~~
danieldk
You can still not have member variables, so the default implementations can
only be implemented in terms of other methods. So it should probably be
classified as 'limited multiple inheritance'. It does have the diamond problem
though.

~~~
scott_s
That was my immediate thought - this is closer to multiple inheritance, as it
introduces the diamond problem:
[https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamo...](https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem)
According to that page, Java forces programmers to resolve the ambiguity by
making it a compiler error. A reasonable approach, I think.

I've done more OO development in C++, and I've found this technique useful -
putting a default implementation in a class which was mostly an interface
because only a small number of subclasses needed specialized behavior.

------
neemsky123
so... when is this coming to android?

~~~
on_and_off
Support for java 8 will come with jack & jill. It might also need a new API
level (24 ? ), which would seriously hamper its adoption. This is why many
people see kotlin as a great thing for the future of Android (even though
kotlin on android could also benefit from java 8 as a target)

------
vvanders
Really like quite a few Lambda stuff in Java8, sadly once you need to touch
any of the intrinsic types it gets ugly real fast. Wanted to do some byte
manipulation with Lambda and I'd be creating a new Byte object for each byte I
touched.

------
ed_blackburn
Where is aysnc await?

~~~
the8472
CompleteableFuture[1] is the closest we got for now in the JDK.

[1]
[https://docs.oracle.com/javase/8/docs/api/java/util/concurre...](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html)

~~~
SloopJon
I just started using CompletableFuture last week. The way each method ties
your lambdas together without a bunch of type boilerplate is really nice. I
still don't have a great handle on all of its methods, though; e.g., what's
the difference between get() and join()?

~~~
kilink
CompletableFuture implements Future, so the get method is an implementation of
Future.get [1].

Anyway, the major difference is that Future.get throws 2 checked exceptions,
InterruptedException and ExecutionException, while CompletableFuture.join does
not throw any checked exception. Instead, it wraps any exceptions in
CompletionException.

[1]
[https://docs.oracle.com/javase/7/docs/api/java/util/concurre...](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html#get\(\))

------
snambi
Gosh... java is getting uglier by these weird syntax.

------
konne88
> Default methods cannot be accessed from within lambda expressions.

Why is that?

~~~
ygra
If I had to guess, it's because the lambda will be expanded at runtime to an
anonymous interface implementation. Then either the runtime part is the
problem or maybe they use a different, but compatible functional interface for
the ad-hoc implementation, which then has no access to default methods on the
one you're assigning to.

~~~
pjmlp
That is not how lambdas work actually work in the reference JVM.

They make use of invokedynamic, there is no expansion taking place as many
think.

[http://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-
th...](http://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood)

------
guelo
The changes are breathtaking. It doesn't feel like Java.

------
dschiptsov
Sorry, I absolutely cannot stand this "modern" meme.

    
    
      (define-syntax stream-cons
          (syntax-rules ()
              ((_ x xs)
                  (cons x (delay xs)))))
    
      (define (stream-cdr xs)
          (force (cdr xs)))
    
      (define (stream-map f xs)
          (stream-cons (f (car xs)) (stream-map f (stream-cdr xs))))
    
      (define (stream-filter f xs)
          (if (f (car xs))
              (stream-cons (car xs) (stream-filter f (stream-cdr xs)))
              (stream-filter f (stream-cdr xs))))
    
      (define (stream-take n xs)
          (if (<= n 0)
              '()
              (cons (car xs) (stream-take (- n 1) (stream-cdr xs)))))
    
      (define (repeat x)
          (stream-cons x (repeat x)))
    
      (define (iterate f x)
          (stream-cons x (iterate f (f x))))
    
      (define (replicate n x)
          (stream-take n (repeat x)))
    
      (stream-take 5 (stream-filter odd?
          (stream-map (lambda (x) (* x x)) (iterate (lambda (x) (+ x 1)) 1))))
    

Not mentioning all these different flavors of Common Lisp streams packages.

As for other features, Scala is around for almost a decade.

~~~
chillydawg
It may not be modern computer science, but it is modern Java. This post is
about modern Java and explains the new (in v8) features very well. What's your
problem?

~~~
dschiptsov
OK, what then is Java < 8?)

The point was that if one has a _proper_ old-school computer science (to
realize the crucial importance of first class procedures and the power of
uniformity 20 years ago) all these modern features are coming for free, to
which the code above is an illustration.

But who cares. There is a whole industry which praised Java for almost two
decades even without these "modern features".

Any PL student of a decent school, if he is not a hypocrite, would tell you
that Java is the worst thing that happened to CS since MS DOS, but who cares
about PL theory or even CS? Availability bias and Cargo Cult is enough.

~~~
jerven
Yes, and now that Java finally has these modern features: people are migrating
to GO who lack many :(

But then LISPs have always been shunned for bad reasons. While crazy bad
languages like C,Java and PHP are picked up by the masses.

~~~
akacase
Your JVM runs on all things written in C and the concurrency primitives are
far more elegant in Go than in Java.

~~~
jerven
Agree and disagree. The thing I was going for is that compscience advantages
don't seem to matter for language adoption. i.e. popularity does not correlate
to compsci purity.

~~~
dschiptsov
Yes, there are different forces in a play.

Let's name it as The Law of a Decent Runtime, and The Law of Attention to
Details, and The Law of a Bazar of Ignorant.))

 _The Law Of a Decent Runtime_ is very simple - evolving a decent runtime is
very costly and time-consuming. It is also related to the second law and to
the inverse of the third - which is a _the Law of Dictature of The Most
Competent_. A decent runtime cannot be produced without talent, time,
financing, competence and attention to details.

The examples are what came out of Xerox Parc, Bell labs, Ericsson and the best
parts of academia (MIT Scheme culture, Scala, Standard ML, LLVM and Haskell,
monads aside).

There are also many in-house (Tensorflow) and sponsored open source porjects
(LLVM, Golang, Julia, Torch, to name a few). Basically, it is about resources
spent on a talent.

What is important distinction - a decent runtime cannot be produced by _the
Bazaar of Ignorant_ (PHP, amateur Java code, SAP, and other "fractals of a bad
design").

The Linux kernel is very special example, because it combines the law of big
numbers, and all these three - it is a product of a whole planet of competent
volunteers and paid developers - unlike PHP or Java ecosystem there is very
high barrier to entry, thanks to _The Dictature of The Most Competent_ .)

 _The law of Attention To Details_ \- is quite obvious, and related to the
first. This is why most of successful projects had a passionate and competent
leader who sets the standards, be it Linux kernel, Erlang, Nginx, Gambit
Scheme, Python, OpenBSD, Redis, Scala, SBCL, PostgreSQL, you name it.

Popularity has nothing to do with it. It is based on the principle of instant
gratification (PHP, MongoDB) or Availability Bias boosted by paid content
brainwashing (Java, SAP, MS) without understanding and preferably any
thinking. Popularity doesn't mean quality at all, be it junkfood or PHP.

~~~
jdmichal
Your _Law of a Decent Runtime_ reminds me exactly of the "Lisp Curse":

[http://www.winestockwebdesign.com/Essays/Lisp_Curse.html](http://www.winestockwebdesign.com/Essays/Lisp_Curse.html)

~~~
dschiptsov
There is another good reading.)

[http://the-programmers-stone.com/the-original-talks/day-1-th...](http://the-
programmers-stone.com/the-original-talks/day-1-thinking-about-thinking/)

------
TurboHaskal
Enjoy these features while you can.

It's a matter of time until your team lead takes a glance at the code-base,
deems them unreadable and "too clever" (as in "where am I going to find cheap
developers now?") and makes you revert all the way back to Java 6.

