6 ms·
Next-gen Java Programming Style
- gdp 17y agoReally good advice. Whenever I encounter Java code that employs some or more of these techniques, I feel a little bit better about the world.
- Retric 17y agoAre you joking? This advice is horrible. He is advocating taking a verbose language and making it even more verbose and far less efficient. Think about what the final in "public final int x;" means in #8. Many Java developers have fallen for the idea that everything is an interface to an interface. However, if you start by trying to get stuff done, you find a most scaffolding is pure waste.
- gdp 17y agoHe is advocating using a style more like modern functional programming languages such as ML, Haskell and F#. The example in #8 is essentially recreating primitive tuple types present in the languages I just mentioned. Given that the overheads on such an object are small, and the garbage collector is good at dealing with short-lived objects, it makes sense to instantiate a new class when it is necessary to mutate it. Your optimiser will love you, and maintaining this style of code is considerably easier.
- Retric 17y agoFunctional programming is ancient. You might be all atwitter about the power of functional code. But, it's an old idea. Emulating the functional style a language that's not based on it provides minimal gain, at the cost of code bloat. PS: Pun was intended to be funny not mean. This really is an old idea, which is occasionally useful, but mostly it's a waste of time, money, and CPU cycles.
- gdp 17y agoSure, but I used the word modern. As in, "of the modern era". There are old functional programming languages and there are young functional programming languages. The fact is that most of the interesting research into programming languages these days goes ends up in functional languages such as Haskell or an ML-variant. And I really don't buy your "bloat" claim. Surely mutating member variables unnecessarily is "bloat". And having redundant getters and setters seems pretty bloated to me. In fact, forcing everything in the universe into a paradigm that largely consists of straight-line imperative code boxed up in classes seems like the ultimate example of bloat, given that one could simply code in an imperative style without using objects. If anything, I would think that the measures suggested would result in marginally smaller code-size, which I assume is the metric you are employing to measure "bloat". In performance terms, I would imagine that these suggestions would result in no performance impact, or some small improvement as it is quite likely that the optimiser will be able to do a better job if you apply this style uniformly. As you say, it might be a minimal gain, but don't we as programmers have something of a responsibility to write the best programs we can and use our tools to the fullest of our abilities, especially when the cost is zero or almost-zero? So what metric are you using here? I assume it's something a bit fuzzy like "readability" or "ease of maintenance"? In that case, you're basically saying "things that are different to what I already do are harder to do", which in addition to being mildly silly, is a total cop-out and is intellectual dishonesty. Too many good ideas in programming languages have been sunk by programmers who hate the idea of not being the expert all of the time, with such behaviour being hidden behind very weak justifications that sound technical, but are actually just about egos. Naturally, this might not be the case with you at all! However, I'd be very interested to know on what objective basis you are making judgements about the awfulness and bloatedness of code (in any language) that employs a more "functional" style.
- Retric 17y agoThere is a reason that research into functional languages is limited to an old or new functional language. Without syntax and compiler support you don't gain any power to offset the limitations. Anyway, the power of OOP is creating intelligent data. You can "automatically" do things with a Point that you need to explicitly do with integers. If you start dealing with a Fixed_Point objects, and Mobile_Point object, you now have bloat with little gain. It's far better to have a "Final" flag on your point, so it will toss an error when you try to change it vs. trying to maintain 2 separate classes. That way if you suddenly need to change your point you have to refractor less code. Granted, if Java's foreach would automatically make helper threads to speed things up then there would be an advantage. But, changing the form without compiler support is pointless. PS: Feel free to test your ideas, but allocating memory is still the enemy of speed. When you create a temporary object outside of the stack it really does slow things down.
- francoisdevlin 17y agoI think it's funny that this is right next to the interview with Rich Hickey :)
- fogus 17y agoIf you look at the source for Clojure you'll see many (if not all) of these techniques used throughout with an additional focus on static classes and methods.
- francoisdevlin 17y agoI guess what I was getting at is that real next gen style uses the JVM, not Java. Down with Java, long live the JVM
- jimbokun 17y agoIn the meantime, if Java teams start implementing these practices, and more Java developers get comfortable with them, making the leap to Clojure, Scala, etc. won't be such a shock. Those languages will just require less boiler plate to write the kinds of programs they are already writing.
- coliveira 17y agoI don't see why people love the JVM if they don't like Java. I agree that it is nice to have lots of libraries for free, but you also have the burden and limitations of living with something that was created specifically for Java. Languages such as Python and Ruby have been much more successful outside the JVM.
- mahmud 17y agoThey love the JVM because it's everywhere they want their apps to be; ubiquity has its own beauty.
- WilliamLP 17y ago> Do not use loops for list operations. I can not get behind this in Java if the filter, fold, or map operation is simply a one-off. (It's another matter entirely though if the power of the functional approach is useful in the situation, say if a filter should be switched dynamically.) To do this for something static though, such as eliminating empty strings or adding an array, is just worse than useless. This is as clear an example as any of programming against the language, not into it. The code is longer, it is slower, and _for a Java programmer_ it is much less clear. Java was explicitly designed not to be a language for showing off cute constructs for their own sake.
- mynameishere 17y agoI don't understand google's awful implementations. In my code by contrast, a map function looks like this: public double foo(double x) { return x*x; } list=Utility.map(this,"foo",list);
- jimbokun 17y agoYou need to do reflection, which probably has performance implications. You also cannot do closures, which you can simulate with anonymous inner classes. Might be worth the trade off in your case, but maybe not for the cases Google has in mind.
- brunomlopes 17y agoNot only does that require reflection, it is very error prone and not refactor-friendly. Just change the type of the list, change the method, and it will blow up on runtime instead of compile time. In my opinion, that goes against the grain of Java (and c#, in a way) of having the compiler doing a lot of checking for you. Google's approach, while more verbose, is a bit safer and more idiomatic.
- bfung 17y agoIn addition to the other comments, the Utility class used in this example defeats the purpose of OO programming that Java is more in tune with. What's to stop the proliferation of these Util classes with static methods? I believe the more Java way would be to extend the List interface to add a map method and implement a corresponding class. To make this less of a pain, extend from one of the JDK provided classes if possible... but yes, it's still a pain.
- Xixi 17y agoI have to admit that the 5th point (Use many, many objects with many interfaces) leaves me thinking... On the one hand I understand where the author wants to go : by implementing many many interfaces you eventually sort of "emulate" duck-typing, while at the same time reinforcing type safety (specially when it comes to String). On the other hand, it sounds like a good way to make something that was verbose to begin with even more verbose... but maybe I'm mistaking. I don't do much Java recently (some GWT/GXT sometimes), but I will probably give it a practical try...
- fogus 17y agoNot necessarily verbose, but moreso a larger codebase. Besides -- all of these extra classes are invisible with D.I. anyway right? ;)
- Xixi 17y agoYou're right, it will grow the codebase more than making the code verbose. And the code will probably be more readable. But have you actually used this in practice ? Is it tractable ? I'm actually thinking of trying this on (a rather old version of) C#, since I'm writing quite lots of code for (an old version of) mono. If only I could use F# sigh
- shiranaihito 17y agoThe proliferation of classes should be manageable if you package them neatly.
- itgoon 17y agoI come from a C# background, learning Java, and I just so happen to be following that process. I don't remember where I picked it up (something in the Spring docs?), but it seemed like a good idea. Short version: yea, it works pretty well. Long version is at this shameless blog plug (no ads): http://itgoon.blogspot.com/2009/08/javas-lots-of-little-files.html http://itgoon.blogspot.com/2009/08/javas-lots-of-little-file...
- jrockway 17y ago
- jimbokun 17y ago"Refactoring is easy, should you need it. If you do not control all the code and it’s usage, you might need to be more careful though." Bloch's Effective Java is wonderful, but if it has a weakness, it might be that it assumes everyone is writing a library to be used by a lot of developers, many of who are outside your organization. The example of public fields in data transfer objects is an example of this. Making the fields public is fine if this code is just for you and your team, because you can always refactor it to use accessors later if you need to. But if this code is in a library used by people outside your organization, introducing accessors later without breaking code will be almost impossible.
- JulianMorrison 17y agoPublic fields like that announce that the object is actually an immutable struct with no internal workings. A need to change it to add computed (or worse, mutable) fields is probably a code smell.
- mcormier 17y agoAlthough I do agree that you shouldn't reassign a parameter I don't agree with using the final keyword everywhere. Any decent koder knows not to modify a parameter. If you want to enforce something like this then parse the code on check in and refuse the check in if a parameter is modified. Don't bloat the kode with a reactionary workaround.
- scott_s 17y agoI program extensively in C++, not Java. I'm in the habit of using the const qualifier wherever appropriate - even if it's a local variable. It's an easy way to tell myself, others and the compiler that what I'm declaring isn't actually a variable, but a named value. I don't see how using a const or final qualifier where appropriate increases bloat.
- profquail 17y agoSo having to write extra code to extend your versioning system to parse whatever language your code is in and then check it to see if you've altered a variable value doesn't increase bloat, but adding the 'final' keyword does? There are other problems with that idea, the first of which is that if someone else takes your code and extends it (say, for an open source project) they won't have the same "checking system" that you have, and so it won't catch their mistakes (while using "final" would). Also, I'm not a Java programmer (I mostly use C# or C), but marking classes/methods/variables in C# as 'sealed', 'final', 'static', etc. actually increases the running speed of that program on the CLR because it is able to skip some safety checks on the IL code when it is executed; I don't know that the JVM does that, but it might be worth looking into.
- gdp 17y agoMost JVM implementations that I am aware of do sane things with respect to optimisation of immutable values.
- Tichy 17y agoI would use final if something is final because it would also help to understand the code. It is a piece of information that something is final. Don't forget that final things can still be changed, though. somethingFinal.setName("teehee"); is still possible even if somethingFinal is final.
- tezza 17y agofinal ... ah yes, the old final. Just remember that final is a signal to the compiler that it can perform certain optimizations on your code. This includes inlining the value. So if you use public static final KEY="value1"; you can get inconsistent class files if you change the value, the copy classes that use KEY 'variable' across selectively. This is most ant webapp and J2EE compiling workflows.
- gdp 17y agoThat sounds like really broken compiler or build script behaviour, rather than something intrinsically wrong with the use of final.
- JulianMorrison 17y agoWhat makes me laugh is the commenter defending getters and setters as encapsulation. No, what getters and setters are is a huge verbose door cut through your encapsulation, turning a class into a mere vending machine.
- bkudria 17y agoAgreed. Probably his confusion stems from the fact that Java can expose properties directly. Eww.
- deleted 17y ago[deleted]
- _giu 17y ago"The Java concurrency primitives like locks and synchronized have been proven to be too low level and often to hard to use" synchronized is not hard to use. it's rather not a good practice to use it, since it will slow down code massively.
- gdp 17y agoConcurrency in general is hard. You'll find that most uses of concurrency in production systems is restricted to very specific patterns. This is probably not a conscious decision, rather it's just very likely that straying too far from very simple models of interaction between concurrent processes is actually just beyond the intellectual scope of most people. I do concurrency theory for a living, and concurrency primitives in Java still give me nightmares.
- uriel 17y agoConcurrency is hard only if you use the common 'pthread-like' model. There are much better alternatives like Erlang and CSP ( http://books.cat-v.org/computer-science/csp/ http://books.cat-v.org/computer-science/csp/ )
- zmimon 17y agoActually synchronized is not that expensive in itself. Especially in modern implementations it's not bad at all. It always used to amuse me how Java developers would go to contortions trying not to synchronize a method and then they'd fill it up with calls to things like Vector (every method synchronized!), StringBuffer (yep, every method synchronized!) and any number of other calls that are synchronized in the default JDK.
- bkudria 17y agoWhat's so great about "Fluent" interfaces? If a language supports named parameters, they're inappropriate, no? (Yes, I know Java doesn't have named parameters, although it and many other languages that don't have it have a work-around with assignment. this is a general question.)
- jrockway 17y agoFluent interfaces suck. Mutating objects is not acceptable, especially when you should pass the correct stuff to the constructor. But this is Java, and it is the only way to cleanly allow inheritable initargs. (Perl/Moose and CLOS get this very right. I only use setters in those languages in very, very rare occasions, and it is usually because I am hacking around something messy.)
- dcminter 17y agoThis is one programmer's opinions dressed up as a definitive list. We might as well be discussing bracing preferences - always futile without evidence. For what little it's worth: 1. Minor benefit as noted. Most devs don't do this. Note that in point 3 his sample loop doesn't declare the loop item final so I doubt he does it all that often either. 2. Ok so far as it goes. 3. What objective benefit am I supposed to get here? If we're pulling preferences out of our bums, I'll go for meaningful names in loop variables thanks. 4. Says who? AT&T braces for the win! 5. Not my preference. Fails the YAGNI principle certainly (which he's apparently in favour of in point 2). 6. Who says it's too hard to use? For simple threading problems the existing tools are more than adequate. 7. Again, what benefit does this convey? It's used in a few places in Java (StringBuffer/Builder) but hasn't proven popular more generally. I suspect there are good reasons for that. 8. Not wildly unreasonable, but Getter/Setter pairs often turn out to be necessary in fairly short order.
- KirinDave 17y agoBizarre advice. Throw away the mutable aspects of Java to try and code in this "new hotness", a pale echo of an OCaml-esque style of programming. In the process you make code that is neither as declarative as functional code, nor elegant as Java code. Stop trying to code like another language and use another language. That's enough for me to discard this article as chaff, but considering it even further, has anyone stopped to ask how the Java runtime and compiler handles these changes? Making new classes instead of mutating existing ones doesn't strike me as an efficient use of the system. Finally, I am so sick of people lamenting being "trapped" in Java. This nonsense of being "trapped" is just a shield for people who don't want to go through the hassle of really using a different language. If I can squeak new languages in at Lockheed Martin on a huge spacerange project who's spec was literally conceived when I was still in diapers, then anyone can do it anywhere if they have the will.
- cturner 17y agoIn some spaces (financial, perhaps military) running the JVM is the only sensible thing to do. It has special status that allows you to skip steps at audit, which allows your customers to install it, it allows you to use libraries and it's really good for cross-platform so long as you don't care about GUIs (and with everyone using web these days, there's no reason to care about GUI).
- tjmc 17y agoTrue, but who's to say you can't use another language in the JVM - eg. JRuby, Jython or Clojure
- fhars 17y agoThe runtime system seems to be fine with this, at least the results for scala code (which compiles to bytecode consisting of many small, mostly immutable classes with shot lived instances) indicate that this style of programming hits a sweet spot for the JIT compiler and the GC (at least for sun's server VM) which has a far easier time inlining things than with code consisting of few big classes with long lived objects.
- igorgue 17y agoPython is newer than Java? :D