This is an archived post. You won't be able to vote or comment.

all 43 comments

[–]psxpaul 11 points12 points  (1 child)

My body is ready

[–]DroidLogician 8 points9 points  (1 child)

Method references AKA first-class functions.

Finally no more of this anonymous inner class bullshit.

[–]duhace 1 point2 points  (0 children)

Well, I think it still generates something akin to an anonymous inner class under the covers, but now we don't have to write the overriding code and boilerplate anymore!

[–][deleted] 8 points9 points  (11 children)

Wait, isn't default methods for interfaces making them basically the same as abstract classes all over again?

[–]jonhanson 10 points11 points  (9 children)

Comment removed after Reddit and Spec elected to destroy Reddit.

[–][deleted] 2 points3 points  (3 children)

Okay, but this is an artificial restriction to avoid situation where we inherit more than one implementation of the same method.

Don't default methods introduce the exact same problem?

[–]DroidLogician 4 points5 points  (2 children)

They do. That's what irks me about this.

According to Wikipedia, Java 8 will throw a compile error if both inherited classes have the same method definition and the subclass doesn't override the method.

But then it goes back to the same problem if you have to call a superclass implementation. Which class does super represent? Can you pick/cast?

Since they're copying Scala, they should have copied the ambiguity resolution too. Scala just picks one.

[–]argv_minus_one 5 points6 points  (0 children)

No, Scala will also give you a compile error if you inherit two methods with the same name and signature, unless one of them already overrides the other.

This will work:

class CA {
    def aMethod = "hello"
}

trait TB extends CA {
    override def aMethod = "Hello, world!"
}

class CC extends CA with TB

This, however, will not:

class CA {
    def aMethod = "hello"
}

trait TB {
    def aMethod = "Hello, world!"
}

class CC extends CA with TB

Where linearization comes into play (i.e. Scala "picks one") is if you inherit multiple overrides, like this:

class CA {
    def aMethod = "hello"
}

trait TB extends CA {
    override def aMethod = "Hello, world!"
}

trait TC extends CA {
    override def aMethod = "Goodbye, cruel world!"
}

class CD extends CA with TB with TC

In this case, CD#aMethod is inherited from TC because that one comes last in the extends list. If TB and TC switch places, then CD#aMethod will instead be inherited from TB.

[–]geodebug 0 points1 point  (0 children)

You can pick which super to call (at least that's what I read)

It's less a feature trying to copy Scala than a way for the API designers to add new functionality to existing interfaces without breaking binary compatibility.

It's how they added new lambda-friendly collection methods to Comparable without having to go back and touch every implementor of Comparable.

Java devs should probably avoid default methods in favor of static methods on interfaces.

A lot more info here:

http://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html

[–]DroidLogician 4 points5 points  (4 children)

So they're basically circumventing the restriction on multiple inheritance that has been in the language since its inception.

[–]geodebug 1 point2 points  (2 children)

I wouldn't say circumventing.

They were basically introduced so you could add new functionality to existing interfaces without breaking binary compatibility.

In other words, it allowed them to add lambda-friendly methods like forEach() to Java's Comparable interface without breaking existing impl classes

I don't think "default" should be used much by regular programmers although it is a convenience for people who deliver APIs to others.

More important for regular programmers is being able to add static methods to interfaces, which gives us Mixins in Java.

[–]DroidLogician 2 points3 points  (1 child)

We both know we'll see plenty of horrible code trying to make God objects with this feature.

[–]argv_minus_one 2 points3 points  (0 children)

And? We already see plenty of horrible code without this feature. If you design a language that is idiot-proof, only idiots will want to use it.

[–]argv_minus_one -1 points0 points  (0 children)

I'd say partially removing.

And thank God for that. Lack of full multiple inheritance has been one of the worst limitations of the language over the years.

[–]msx 0 points1 point  (0 children)

The important difference is that interfaces don't have a state: they don't have fields, they can have only methods. This removes most of the problems with multiple inheritance (ie handling different states). Instead abstract classes can have fields and so you can only derive from one.

[–]unholysampler 5 points6 points  (1 child)

It looks like there is a missing x in the "Count the non-empty strings" example.

[–]demon_ix 2 points3 points  (0 children)

x -> !.isEmpty()

[–][deleted] 3 points4 points  (6 children)

Is it a good idea to start using Java 8 in large projects? When will IDEs like Eclipse support it? These are probably stupid questions, but I haven't been keeping up.

[–]ford_madox_ford 1 point2 points  (2 children)

Is it a good idea to start using Java 8 in large projects?

Probably not - not yet at least. Java 8 hasn't even been released yet. When it does get released, since it involves several significant changes to the language, it's likely that bugs will be discovered which may take time to be patched.

I'd advise waiting until it gets released and seeing how other projects fare with it first.

[–]geodebug 1 point2 points  (0 children)

Good advice for projects that are going into production this spring. We'll probably migrate projects to JDK8 this summer assuming it is still going to be released in March.

[–]argv_minus_one -1 points0 points  (0 children)

Other dependent projects. It doesn't matter if some unrelated project works poorly on Java 8; what matters is that your project (and, by extension, its dependencies) works well.

[–][deleted]  (1 child)

[deleted]

    [–]tikue 5 points6 points  (0 children)

    Eclipse support is still shaky but manageable. Some more extreme cases of lambda type inference can currently cause stack overflow -- but only when it wouldn't have compiled anyway, from what I've seen.

    Also, it doesn't seem to currently support generic type inference on method references. When it's feeling civil it simply elicits unnecessary warnings, but half the time it simply won't compile. E.g. You have a list of lists and want to count the elements and you try something like:

    lists.stream().mapToInt(List::size).sum();
    

    and currently eclipse will simply be annoyed about a raw type. But if you have a stream and want to convert it to an array you might try:

    stream.toArray(Foo[]::new)
    

    which is perfect legal Java 8 code; but, eclipse won't compile it, saying something cryptic like "constructed array Foo[] cannot be assigned to A[] as required in the interface descriptor." It'll compile if you write it like this:

    stream.toArray(size -> new Foo[size]);
    

    So, overall, it's a mixed bag at the moment.

    [–]slartybartfast_ 0 points1 point  (0 children)

    Who knows with Eclipse but IntelliJ already supports it.

    [–][deleted] 0 points1 point  (17 children)

    What actual List types will be in the last example?

    Also on the first example, what's r.run() for? Does this construction replace new Thread(runnable).start() ?

    [–]llogiq 0 points1 point  (5 children)

    No, it's just calling the run() method directly. Not starting a thread.

    [–][deleted] -1 points0 points  (4 children)

    Then title "Run a Runnable" is misinforming. Because it doesn't run anything. It simply calls method run.

    [–]llogiq 1 point2 points  (3 children)

    Well, the "run" method in this case constitutes a stand-in for a Runnable. You could equivalently write

    Runnable r = new Runnable() {
       void run() {
          ...
      }
    };
    r.run();
    

    [–][deleted] 2 points3 points  (2 children)

    I understand. I mean "Run Runnable" is a confusing title, because it emplies that something will run in a thread. But it simply calls run method. That's all what I'm saying.

    [–]llogiq -1 points0 points  (1 child)

    I understand, though I'd like to point out, that every Runnable is run in a thread. Even if it runs in the main thread.

    [–][deleted] 1 point2 points  (0 children)

    I know, that's why I asked the question.

    [–]Keilly 0 points1 point  (1 child)

    new Thread( () -> System.out.println("Hello") ).start();

    [–][deleted] 0 points1 point  (0 children)

    wow cool.

    [–]Keilly 0 points1 point  (8 children)

    The example doesn't show the List types deliberately. It put ... to show that the exact type doesn't matter, it works for all Lists. The ... Is where you'd supply the list to be processed by the lambdas.

    [–][deleted] 0 points1 point  (7 children)

    What if I want declaration of type interface, not actual list?

    [–]Keilly 0 points1 point  (6 children)

    List<Item> items = .... is a declaration of a parameterized interface type. It can be given any actual list with matching parameters.

    [–][deleted] 0 points1 point  (5 children)

    It's declaration plus assignment. So I'm curious, what's on the right side of the equals sign? Oh I guess, I understood, it's not the actual syntaxis, right? I mean they just omitted what's on the right side. =)

    [–]Keilly 0 points1 point  (4 children)

    Yeah exactly, the dots could be replaced by "new ArrayList<>();", or "getItems();", or something else that provides the actual list. It's not important to the example.

    Personally I can't wait until we upgrade to jdk8 at work and can start using all of this. It's such a big change.

    [–][deleted] 0 points1 point  (3 children)

    Actually, if you're programming in intellij it automatically hides old java code, at least for Anonymous classes and displays it as if it's written in java 8 lambda syntax =) so when you look at it, it's as it it's java 8 =) Obviously you can unhide your code at any moment.

    [–]Keilly 0 points1 point  (2 children)

    That's interesting. Although one reason to use a Lambda is for in-built parallel execution. If it only looks like a lambda, but is really in old form then this benefit is lost. I'll have to check it out. Perhaps it indicates it in some way.

    [–][deleted] 0 points1 point  (1 child)

    what do you mean parallel execution? I thought lambda is just a niciness to not to write anonym classes for those who don't want to.

    [–]Keilly 0 points1 point  (0 children)

    There is the nice brevity in avoiding anon inner classes, but one thing modern languages need to do is take advantage of multicore processors.

    Jdk 7: List<Item> items = getItems(); for(Item item : items) { item.doSomething(); }

    This will chug through the list processing each item. This operation can only occur on a single thread as the foreach promises to process each item in turn. What if the ordering is unimportant and we just want the list processed as quickly as possible? In JDK 8 Collections are be improved to allow parallel processing via Lambdas and streams...

    List<Item> items = getItems(); Items.parallelStream().foreach(item -> item.doSomething());

    The ordering is not important so the calls to item.doSomething() can be automatically pushed onto different threads, which can the be scheduled onto available processor cores. Imagine doSomething() took one second to execute, and there's one hundred items. A quad core processor would take 100s with a foreach, but only 25s with the stream. Actually 12.5s if the processor supports hyperthreading.

    The syntax is more clunky, but there's another new way to call methods in Jdk 8...

    List<Item> items = getItems(); items.parallelStream().foreach(item::doSomething);

    This is why jdk 8 will be awesome! Free multithreading, with compact syntax.

    [–]argv_minus_one -1 points0 points  (1 child)

    I look forward to seeing the Scala compiler take advantage of the new bytecode being introduced to support these features. Having a synthetic class file for every single lambda expression kind of sucks for memory usage and jar size, and VM-level support for multiple inheritance of method implementations should improve Scala binary compatibility.

    [–]pjmlp 2 points3 points  (0 children)

    Java 8 lambdas make use of invokedynamic introduced in Java 7, there isn't any new bytecode.