At
Data Geekery, we love Java. And as we’re really into
jOOQ’s fluent API and query DSL, we’re absolutely thrilled about what Java 8 will bring to our ecosystem.
Java 8 Friday
Every Friday, we’re showing you a couple of nice new tutorial-style Java 8 features, which take advantage of lambda expressions, extension methods, and other great stuff.
You’ll find the source code on GitHub.
The dark side of Java 8
So far, we’ve been showing the
thrilling parts of this new major release. But there are also caveats. Lots of them. Things that
- … are confusing
- … are wrong
- … are omitted (for now)
- … are omitted (for long)
There are always two sides to Java major releases. On the bright side, we get lots of new functionality that most people would say was
overdue. Other languages, platforms have had generics long before Java 5. Other languages, platforms have had lambdas long before Java 8. But now, we finally have these features. In the usual quirky Java-way.
Lambda expressions were introduced quite elegantly. The idea of being able to write every anonymous SAM instance as a lambda expression is very compelling from a backwards-compatiblity point of view. So what
are the dark sides to Java 8?
Overloading gets even worse
Overloading, generics, and varargs aren’t friends.
We’ve explained this in a previous article, and also
in this Stack Overflow question. These might not be every day problems in your odd application, but they’re very important problems for API designers and maintainers.
With lambda expressions, things get “worse”. So you think you can provide some convenience API, overloading your existing
run()
method that accepts a
Callable
to also accept the new
Supplier
type:
static <T> T run(Callable<T> c) throws Exception {
return c.call();
}
static <T> T run(Supplier<T> s) throws Exception {
return s.get();
}
What looks like perfectly useful Java 7 code is a major pain in Java 8, now. Because you cannot just simply call these methods with a lambda argument:
public static void main(String[] args)
throws Exception {
run(() -> null);
// ^^^^^^^^^^ ambiguous method call
}
Tough luck. You’ll have to resort to either of these “classic” solutions:
run((Callable<Object>) (() -> null));
run(new Callable<Object>() {
@Override
public Object call() throws Exception {
return null;
}
});
So, while there’s always a workaround, these workarounds always “suck”. That’s quite a bummer, even if things don’t break from a backwards-compatibility perspective.
Not all keywords are supported on default methods
Default methods are a nice addition. Some may claim that
Java finally has traits. Others clearly dissociate themselves from the term, e.g. Brian Goetz:
The key goal of adding default methods to Java was “interface evolution”, not “poor man’s traits.”
As found on the lambda-dev mailing list.
Fact is, default methods are quite a bit of an orthogonal and irregular feature to anything else in Java. Here are a couple of critiques:
They cannot be made final
Given that default methods can also be used as convenience methods in API:
public interface NoTrait {
// Run the Runnable exactly once
default final void run(Runnable r) {
// ^^^^^ modifier final not allowed
run(r, 1);
}
// Run the Runnable "times" times
default void run(Runnable r, int times) {
for (int i = 0; i < times; i++)
r.run();
}
}
Unfortunately, the above is not possible, and so the first overloaded convenience method could be overridden in subtypes, even if that makes no sense to the API designer.
They cannot be made synchronized
Bummer! Would that have been difficult to implement in the language?
public interface NoTrait {
default synchronized void noSynchronized() {
// ^^^^^^^^^^^^ modifier synchronized
// not allowed
System.out.println("noSynchronized");
}
}
Yes,
synchronized
is used rarely, just like final. But when you have that use-case, why not just allow it? What makes interface method bodies so special?
The default keyword
This is maybe the weirdest and most irregular of all features. The
default
keyword itself. Let’s compare interfaces and abstract classes:
// Interfaces are always abstract
public /* abstract */ interface NoTrait {
// Abstract methods have no bodies
// The abstract keyword is optional
/* abstract */ void run1();
// Concrete methods have bodies
// The default keyword is mandatory
default void run2() {}
}
// Classes can optionally be abstract
public abstract class NoInterface {
// Abstract methods have no bodies
// The abstract keyword is mandatory
abstract void run1();
// Concrete methods have bodies
// The default keyword mustn't be used
void run2() {}
}
If the language were re-designed from scratch, it would probably do without any of
abstract
or
default
keywords. Both are unnecessary. The mere fact that there is or is not a body is sufficient information for the compiler to assess whether a method is abstract. I.e, how things should be:
public interface NoTrait {
void run1();
void run2() {}
}
public abstract class NoInterface {
void run1();
void run2() {}
}
The above would be much leaner and more regular. It’s a pity that the usefulness of
default
was never really debated by the EG. Well, it was debated but the EG never wanted to accept this as an option.
I’ve tried my luck, with this response:
I don’t think #3 is an option because interfaces with method bodies are unnatural to begin with. At least specifying the “default” keyword gives the reader some context why the language allows a method body. Personally, I wish interfaces would remain as pure contracts (without implementation), but I don’t know of a better option to evolve interfaces.
Again, this is a clear commitment by the EG not to commit to the vision of “traits” in Java. Default methods were a pure necessary means to implement 1-2 other features. They weren’t well-designed from the beginning.
Other modifiers
Luckily, the
static
modifier made it into the specs, late in the project. It is thus possible to specifiy static methods in interfaces now. For some reason, though, these methods do not need (nor allow!) the
default
keyword, which must’ve been a totally random decision by the EG, just like you apparently cannot define
static final
methods in interfaces.
While visibility modifiers were
discussed on the lambda-dev mailing list, but were out of scope for this release. Maybe, we can get them in a future release.
Few default methods were actually implemented
Some methods would have sensible default implementations on interface – one might guess. Intuitively, the collections interfaces, like
List
or
Set
would have them on their
equals()
and
hashCode()
methods, because the contract for these methods is well-defined on the interfaces. It is also implemented in
AbstractList
, using
listIterator()
, which is a reasonable default implementation for most tailor-made lists.
It would’ve been great if these API were retrofitted to make implementing custom collections easier with Java 8. I could make all my business objects implement
List
for instance, without wasting the single base-class inheritance on
AbstractList
.
Probably, though, there has been a compelling reason related to backwards-compatibility that prevented the Java 8 team at Oracle from implementing these default methods. Whoever sends us the reason why this was omitted will get a
free jOOQ sticker :-)
The wasn’t invented here – mentality
This, too, was criticised a couple of times on the lambda-dev EG mailing list. And while writing this
blog series, I can only confirm that the new functional interfaces are very confusing to remember. They’re confusing for these reasons:
Some primitive types are more equal than others
The
int
,
long
,
double
primitive types are preferred compared to all the others, in that they have a functional interface in the
java.util.function package, and in the whole Streams API.
boolean
is a second-class citizen, as it still made it into the package in the form of a
BooleanSupplier
or a
Predicate
, or worse:
IntPredicate
.
All the other primitive types don’t really exist in this area. I.e. there are no special types for
byte
,
short
,
float
, and
char
. While the argument of meeting deadlines is certainly a valid one, this quirky status-quo will make the language even harder to learn for newbies.
The types aren’t just called Function
Let’s be frank. All of these types are simply “functions”. No one really cares about the implicit difference between a
Consumer
, a
Predicate
, a
UnaryOperator
, etc.
In fact, when you’re looking for a type with a non-
void
return value and two arguments, what would you probably be calling it?
Function2
? Well, you were wrong. It is called a
BiFunction
.
Here’s a decision tree to know how the type you’re looking for is called:
- Does your function return
void
? It’s called a Consumer
- Does your function return
boolean
? It’s called a Predicate
- Does your function return an
int
, long
, double
? It’s called XXToIntYY
, XXToLongYY
, XXToDoubleYY
something
- Does your function take no arguments? It’s called a
Supplier
- Does your function take a single
int
, long
, double
argument? It’s called an IntXX
, LongXX
, DoubleXX
something
- Does your function take two arguments? It’s called
BiXX
- Does your function take two arguments of the same type? It’s called
BinaryOperator
- Does your function return the same type as it takes as a single argument? It’s called
UnaryOperator
- Does your function take two arguments of which the first is a reference type and the second is a primitive type? It’s called
ObjXXConsumer
(only consumers exist with that configuration)
- Else: It’s called
Function
Good lord! We should certainly go over to Oracle Education to check if the price for
Oracle Certified Java Programmer courses have drastically increased, recently… Thankfully, with Lambda expressions, we hardly ever have to remember all these types!
More on Java 8
Java 5 generics have brought a lot of great new features to the Java language. But there were also quite a few caveats related to type erasure. Java 8’s default methods, Streams API and lambda expressions will again bring a lot of great new features to the Java language and platform. But we’re sure that
Stack Overflow will soon burst with questions by confused programmers that are getting lost in the Java 8 jungle.
Learning all the new features won’t be easy, but the new features (and caveats) are here to stay. If you’re a Java developer, you better start practicing now, when you get the chance. Because we have a long way to go.
Nonetheless, thigns are exciting, so stay tuned for more exciting Java 8 stuff published in this
blog series.
Are you in for another critique about Java 8? Read
“New Parallelism APIs in Java 8: Behind the Glitz and Glamour” by the guys over
Like this:
Like Loading...
If default methods were allowed to be final, you could not implement 2 different interfaces containing the same method anymore as soon as one is final and you want to choose the other implementation. `synchronized` has to do with concurrent access to shared state, and interfaces don’t have any state, so I find it quite normal to let that as a choice to the implementation. And since default methods can’t be final, you can always override the default methods just to make them synchronized.
Good point concerning
final
, but this problem already exists as you can’t implement bothCollection
and something declaring long size().I disagree with
synchronized
as you can synchronize onclass X {}
which has no state either. You can also enclose the whole method body insynchronized (this)
which is AFAIK equivalent. I’d guess this should work for interfaces as well.Yes, except that putting
synchronized
into the signature formally makes it part of the method contract.I can see hwo this might have been a compelling enough argument for the expert group to leave
final
out of the game for interfaces. Yet, you may run into similar issues if 2 different interfaces contain the “same” method returning incompatible types, already since Java 1.0:You cannot implement both of the above interfaces. So in my opinion, the added value for API designers of having
default final
methods outweights the rare edge-cases, where people run into this kind of issue.Synchronized: It might be used as a contract for implementations, similar to
Hashtable
which made that a contract for subtypes likeProperties
. Agreed, this isn’t very contemporary and would probably be useful only in very remote edge-cases.Actually,
synchronized
in the method signature is rather misleading as it doesn’t get inherited. You could consider it to be a combination of an implementation detail with a documentation, but a collection interface method documenting all implementations to be synchronized is pretty much useless (neitherConcurrentHashMap
norImmutableMap
would comply; actually no usable class would). You may require all implementations to be thread-safe in a sense, but there are too many useful options (andsynchronized
doesn’t belong to them).Good point. I hadn’t thought of that.
Why would you overload Callable with Supplier, since both have the same lamba signature?
Also, I believe equals and hashcode are never added as default methods on interfaces because default methods always defer to methods on classes. As both are implemented on Object, the default would never be used.
Not too sure about listIterator, but it would have required moving the method from AbstractList to List, which might have caused binary backwards incompatibility?
Just because we now have lambdas doesn’t mean that lambdas is all we ever do. The two methods are very different methods. If you’ve written a ton of JDK 6 concurrent API with lots of Callables, and now you write a ton of JDK 8 streams API with lots of Suppliers, you *might* just think that you should overload this method for convenience. Of course, you shouldn’t, but this is not very obvious at first.
You’re right, and in fact, the compiler prevents this. You’re not allowed to have such default methods in interfaces. While this makes sense from a language perspective, it’s kind of weird because all sorts of contracts for
equals()
andhashCode()
are already overwritten. Why not be able to provide a default implementation for such a contract? I guess this shows that the whole notion of methods fromjava.lang.Object
is a bit quirky (e.g. thewait()
methods)Interesting thought. Could you show an example?
Another problem with adding default implementations of methods which already existed on the interface previously is that it could break backwards compatibility. For example, there might have been code that depended on MyList’s equals method being the default implementation from Object. While such code is a clear violation of spec, Oracle goes out of their way to avoid breaking code that already “works”.
As for listIterator – that’s a harder one to figure out – hard to imagine code depending on a NoSuchMethodError. I don’t think binary compatibilty would be an issue, since it appears that default methods are invoked with invokeinterface when called against the interface, and invokevirtual when called against the class, just like other methods.
While that is a remote possibility, I doubt that this is a motivation for the expert group to have decided upon things the way they are. Other comments on this post have indicated that no matter what default method matches
Object.equals()
, the actualObject.equals()
implementation will always take precedence. It is simply not possible to override a method from the concrete class hierarchy from an interface. Hence, it simply doesn’t make sense to implement a defaultList.equals()
method.Yes, that’s a better example than
equals()
Oracle not adding the default methods to
List
should be no problem as you could do it inYourList extends List
. Unfortunately, many of them usemodCount
, which you can’t have in an interface.You could provide it in the implementations (it’s just one field) and use abstract accessors in
YourList
, but they would have to be public. Too bad they din’t fix the visibility problem.Yes, you could, of course.
Which leads to the other feature omission that you’ve mentioned, too: visibility modifiers on default methods (or on any interface methods). That, too was discussed on the lambda list, and omitted because of the time constraints, and some uncertainty about how to handle package visibility on interface methods (e.g. by introducing a package keyword).
Agreed. Interfaces forcing all methods to be
public
was a terrible idea and it’s pity it wasn’t fixed now. Given thatpackage
is already a keyword and that it can’t appear anywhere but in the package declaration, it’d be no problem to recycle it for access control, although recyclingdefault
feels better (which is not an option anymore; I agree with your arguments).What could be the purpose of a synchronized method on a interface? After all the interface does not have state, so what would you be synchronizing access to?
Also, final interface methods? Does that make sense? After all the whole idea of an interface is to create implementations of it. You are saying that you want to seal an interface method because it has a default implementation?
One reason is to establish a contract already on the interface level (why not…). Another is: Because you can. I mean, you can write this:
And because this can be done, why not just allow promotion to the API even if it’s useful only in remote edge-cases?
Yes, because that’s the whole point of
final
. Imagine overloaded convenience methods:Let me play the Devil’s advocate here, just for the purpose of making the conversation interesting.
In the case of the synchronized suggestion, this could be something that could have been argued of the traditional interfaces prior to the JDK 8 as well, but we know that keywords like synchronized, final and strictfp should go in concrete implementations and not interfaces because otherwise it would force every implementor to pay a price they may not be interested in. That question would be what if I want an implementation of such interface not to be synchronized. Also, is hard to reason about synchronization in an interface, I mean, you don’t even know what the state of the implementor would be, how do you you synchronizing this would prevent a race condition.
They actually David Holmes and Joseph Darcy discussed some of this in the Lambda Mailing List (https://mail.openjdk.java.net/pipermail/lambda-dev/2012-October/006084.html)
On the other hand, final methods on an interface are kind of counterintuitive for me since the hole purpose of the interface is to be implemented. I think such weird cases should probably fit better in an abstract class, but if that were the case, then we should not only support final, should support other modifiers like protected and private as well. Ultimately, an interface would be just like a class, but without state. I guess with interface now supporting implementations, it becomes a gray area how far interfaces should go. Time will tell, I guess, and this is what the expert group is expecting. You can see Brian Goetz said:
“[…] we expect that this will inevitably create pressure for
additional features in interfaces, like, say, private methods. Some of
these we may try and anticipate by including in this round; others we
may wait for usage patterns to emerge […]”
https://mail.openjdk.java.net/pipermail/lambda-dev/2011-December/004361.html
Thanks for digging up those links. I wasn’t aware of the first one where
synchronized
andstrictfp
were discussed. One can also see the importance that was given to this discussion :-) Myself, I wouldn’t want to argue aboutsynchronized
(orstrictfp
, which I had forgotten in the blog post) too long. In the end of the day, the added value for any API designer is marginal, as opposed tofinal
and visibility modifiers, which would be an essential further evolution of interfaces being classes without state – which they should be, in my opinion, and which is again an argument against thedefault
keyword.Another argument in favour of
final
in interfaces is the possibility to prevent shadowing ofstatic
methods that may now be declared in interfaces. This type of shadowing is hardly every useful, and in my opinion, a complete anti-pattern – i.e. by default, allstatic
methods should be written asstatic final
, also in interfaces. But that obviously won’t happen in the JDKGood article, made my brain work for a while :)
But, even thought I started learning Java after working with C++ for 6-7 years just 4 months ago, I think I’m able to give several details/corrections here.
First, I didn’t think of ambiguous method call with lambdas and thanks for pointing it out, but what’s wrong with call((Functor) (Lambda_expression)) syntax? For me it looks perfectly clean, in spite of being a little bit bigger. It’s perfectly readable and developer’s intention is obvios. Isn’t the readability the only thing which matters? :)
Second, about synchronized. As Maaartinus pointed out, it isn’t part of method’s contract, because it is not being inherited. So, it has no use in interfaces. Moreover, as Interface has no state (it can’t have instance or even static fields) there is no point in synching on instance or static methods. So, the only case in which you may want to synchronize something in interface’s methods is when you use some shared objects: IO streams, Collections, etc. Hence, you need to synchronize on these particular objects using synchronize block. It will also make your intention easy to understand for other developers.
So, I don’t think that you will ever need to make up the lack of synchronized methods with synchronized(this) or synchronized(I.class). I believe my point on this particular topic is very solid.
Now, about static methods in interfaces. Nothing random about it – actually, it’s even more intuitive than synchronized keyword. The tricky thing about static methods is that they are completely out of inheritance tree, which makes both default and final keywords completely useles.
If you write something like this:
And then try to execute I2.out() – the compiler won’t find out() method in I2. If you try to “override” it – you just create completely new static method. So, here is no point in making them final/default.
Now, default Object’s methods in interfaces… You’re correct that wherever conflict between Class’ and Interface’s default methods arrises – the former will be prefered. The reason is backward compatibility and is very old one. When Java was being designed it was supposed to be much easier to learn than C++, right? One of the toughest concepts was multiple inheritance.
E.g., in C++:
To get rid of it, interfaces were sepparated from classes in Java. Now, if interface Parent_I declared method X and class Parent_C implements the same method, then class “Child_C extends Parent_C implements Parent_I” will use Parent_C’s implementation. So, the same happens in Java 8 with default methods. You already pointed out that Java 8 is too complicated in some places (and I absolutely agree), but letting you implement Object’s methods in interfaces probably would make things even worse and could move us closer to C++’s multiple inheritance.
One more interesting point about final + default. Well, first of all “default” means that it is the most general method’s implementation, API designer could think of. But you’re encouraged to override it with what is supposed to be the most effective for your use case. So, it probably shouldn’t be final.
But what is more important, is the conflict between two interfaces if finals were allowed. Let’s look at the example:
The compiler won’t let it pass – it can’t figure out what to do in C1.doX()! But no problem, you can fix it:
But wait! What if we actually could make default methods final? We would not be able to override them in C1. So, how could we use I1 and I2 interfaces together than?
And finally, even though I agree that Java 8 asks you to remember a lot of stuff you would prefer not to keep in your head, I don’t think that Predicate, Consumer, Supplier, etc.. are so complicated. I think the naming is pretty obvious and even if you have to use them – there is no problem to figure out which one is your choise. In my opinion, it is one of the cleanest parts of Java 8 :)
But, as you said, Java is more and more complicated to learn. I have the same impression and it’s quite fresh because I started with Java 6 at my previous job few months ago, then prepared for OCJPs for Java 7, and after that OCJP 8 became available – so I started to learn Java 8. And yes, even though some good stuff has been added, the language became much more complicated.
Usually, one expects new features to be somehow intuitive to learn, but in Java all the releases seem to bring a lot of exceptions and underdone stuff with them. E.g., Generics without support for primitive types (since Java 5) lead to lots of specialized classes in Java 8 (IntPredicate, mapToLong, IntStream, etc…); this new “effectively final” stuff; default + Object’s methods; just to give a few.
Agreed. Java 8 makes it also easy to write a simple stuff in an unreadable way by overusing the functional stuff (or misusing it for side effects). Sadly, the specialized classes (
IntPredicate
,QuaternaryDoubleObjectIntLongCharFunction
, …) will stay long after the primitive generics problem gets solved.I guess, they should’ve deprecated a few things, like
synchronized
,wait
,notify
,notifyAll
, (and alsoDate
,StringBuffer
,Vector
at al.) and threaten to remove them soon. Why? There’s no reason to synchronize on an arbitrary object and it’s no good idea either. See also https://projectlombok.org/features/Synchronized.html.Moreover,
wait
at all pollute the namespace.Thanks for taking the time to comment.
Remember generics? Before generics, we used to cast every type and their dog to some subtype, e.g. when unwrapping them from collections. I dare say no one working with Java on a daily basis misses explicit casting. If you really want to argue about what’s wrong with the
call((Functor) (Lambda_expression))
syntax, I challenge you to tell me what’s wrong with the following syntax:Clean, a bit bigger, perfectly readable, intention is obvious… ;-)
Clearly synchronized on default methods would raise more questions than it would solve problems. The argument here was a bit academic, showing that we are inheriting a lot of legacy in a highly irregular language that causes lots of confusion when new features are added, differently.
In my opinion, it wouldn’t be unwise to forbid
synchronized
on class methods (emitting a warning for now, removing support in Java 11 or so), just to be consistent.They are indeed “out of the inheritance tree”, which was a conscious decision at some point in their design, yet again a very irregular decision. Perhaps it only means that allowing for static methods to be linked from subclasses was always a mistake:
Again, the criticism here is the fact that all of this legacy is still lying around when the language evolves into a very inconsistent new direction. Perhaps it should be forbidden to reference
C1.out()
viaC2.out()
to make the language more regular.I do understand this rationale and I do understand that many of the early Java language designers must have been very terrified by their earlier C++ experience. But it was a time when few people recognised composition over inheritance. Today, our fear has diminished and we can handle multiple inheritance (of behaviour) much more easily in our abstractions, mostly by avoiding it entirely.
The Scala collection libraries, on the other hand, are a good example where this has been applied in a good way. The example you’re showing is a corner case and it happens also with “ordinary” Java:
This is nothing new, but it’s OK. A small price to pay. You simply can’t implement both
I1
andI2
at the same time. Big deal…You’re arguing your point from the perspective of the fact that
Object
already has those methods. I’m arguing from the point of view thatObject
should have never had those methods in the first place, instead of making quirky rules about some “special” methods that can never have any default, even if that would have been terribly useful fortoString()
,hashCode()
, andequals()
(which should be default methods on new typesToStringable
,Hashable
, andEqualable
).Apply your argument to class methods and it would work just the same. In fact, if any such argument is valid, then only either both class and interface methods should be allowed to be
final
, or none. All other solutions are inconsistent and quirky, requiring much more complex explanations about what each different type of object really is and what it isn’t. This is fine in every day work, but it complicates the language unnecessarily.I understand this argument, but as an API designer, I know my tools (the language), and I won’t make this mistake. Besides, see again my own example:
The argument is bogus. Language users can shoot themselves in the foot. It’s not the job of a language designer to educate their users about design principles.
So you deny there is some cognitive friction in remembering all of the following, for example:
I mean, why is “ToIntFunction” a concept that is still “sufficiently Function-ish”, but “Predicate” is not, such that neither the term “Function” is repeated, nor “apply”, nor does “Predicate” make any reference to the fact that a primitive
boolean
is returned? I would have expected:Well, we’ll all live with this now. But as an API designer, I usually take a moment to find the right one. From the type name itself, I simply don’t know for sure what the best choice is.
Well, I have never said that the changes are not confusing. I meant they can be logicaly deduced given some OOP and syntax knowledge.
Old anonymous class syntax was too noisy and it obfuscates the desire to implement one single function behind creation of a new class. Of course, it seems clean for you as you’re used to it after years of Java experience. The moment when you see the construct, you unconciously look for the overriden method. But no, it’s not clean enough. As I mentioned, I have very small Java experience and for me the new lambda syntax looks much better.
Moreover, somewhere in heart I still hope that one day lambda functions internally will be REALLY implemented like functions. Not like class methods. Just for sake of optimization.
I was probably somewhere in high school when Java 1.5 has been released :) , but as far as I understand, the main problem was “unsafe type casting” rather than some additional typing. So, you could place a Cat into a Dog cage. It’s not the same with lambdas. You just help the compiler a little bit here.
I totaly agree that statics are confusing. Static methods in classes were designed really bad. Static methods in interfaces fixed the mistake, but I don’t sure if it worth it. So, now:
– with classes you can call superclass’ method via subclass. And also, you can call static method via object reference: instance.static_method(). This one I particularly hate, as it breaks readability a lot.
– with interfaces both problems were solved, but inconsistency was introduced.
No, my argument with finals won’t work the same with classes :) But this one is my personal opinion and may be wrong.
Class is what an object primary is. And sometimes you know how the whole kind of such objects should behave. E.g., all the vehicles will rotate wheels on moving , etc. So, you may wish to make it final.
But interfaces, on the other hand, represent some secondary behaviors common among separate class hierarchies. And any class in particular will have to implement it on its own, because only its developer knows how to do it. Here is the lack of finals.
About Predicate’s, Function’s, etc methods… you have no idea how angry I was with methods’ naming in Java. After moving from C++ collections to Java collections I couldn’t understand why you add() ellements into Sets and Lists, BUT you put() them into maps. Then, I met concurrent collections and especially BlockingQueue interface – I was extremely dissapointed to explore all the add, put, offer, take, remove, pull, element, etc.. methods. And all of them with different behaviours for different subclasses. And finally, I had to remember these java.util.functions.* SAMs.
I have no idea why the language, wich was positioned as crossplatform and EASIER C++ clone, became so inconsistedly designed :(
I never said that. I have always dreaded anonymous classes. I just opposed your argument in the case of what appears to be an unnecessary lambda cast to me.
You could use Scala in the meantime. I doubt that Java will be really state-of-the-art functional any time soon… Scala on the other hand has built-in support for real “anonymous” functions and structural types. Here’s how you can implement anonymous structural types with Java 8: http://benjiweber.co.uk/blog/2015/08/07/anonymous-types-in-java. Horror!
Welcome to this equally opinionated (and possibly wrong) blog, then! :-)
I understand this argument, but it is biased by a presumed preference for a certain style of programming. There is absolutely nothing wrong with the following style (which I would have liked):
The point being that there is absolutely no reason to override the convenience method
foo(String)
. Onlyfoo(Reader)
should ever be implemented. People have done this with abstract classes all the time. Other languages do this with extension methods. It’s a very useful technique, and I don’t see why anyone would educate me not to proceed with this technique. Or to put it in your words: Sometimes, I know how the whole kind of such convenience methods should behave. E.g. allString
convenience methods that correspond to equivalentReader
methods will wrap theString
in aStringReader
. I really don’t see how your argument applies to vehicles and wheels but not to the above.So, this is why I argue that either
final
should be possible everywhere or nowhere, for consistency.I can imagine :-) The main reason for Java’s success is the fact that it is the default language on top of the JVM and the JVM totally rocks… The libraries are really mediocre, at best. See also this rant about the lack of functionality in the Stream API
java 8 , lambda provides deferred execution, Will that cause a problem in case of concurrency?
What kind of problem would you be expecting?