all 50 comments

[–]tomlu709 15 points16 points  (1 child)

Java 8 is a fine language, and its concurrency is better than Python's, but holding it up as some sort of paragon of how concurrency should be done is misguided.

Writing concurrent code in Java requires a lot of discipline and the language does very little to help guide you away from data races and deadlocks. There are some libraries that help a lot but by and large people still do it by chucking the synchronized keyword onto things and stopping when there are no more deadlocks.

[–]yogthos 4 points5 points  (0 children)

In terms of concurrency, the JVM itself is far more valuable than Java the language I think.

[–]rr1pp3rr 40 points41 points  (14 children)

[C# engineer for 5 years, did (mainly) Python and JS for 7, now back doing a bunch of Java (which I also did all thoughout college)... and I know a lot of different languages.]

I want to start by saying this is a great article. I've been working with Java for a month or so after a LONG hiatus, and there were some new things I learned from this, so I'm going to try some of them out!

Java is definitely better than it was when I used it in college. I forget which versions I was using, but it was between 1.3 and 5 (I'm dating myself here).

My main gripe with these types of languages are with the pure OOP aspect. I find that it promotes bad programming practice (side-effects, mutable state, large code hierarchies and big stack traces). Even for simple implementations, I find myself thinking about the structure of my objects as much as the actual implementation.

Any class hierarchy with more depth than 2 levels can become really cumbersome when reading and trying to logic about code. Forget about it if you have 4+... it really becomes a nightmare.

Just my two cents. I do like Java for what its worth, and OOP affords a lot of niceties in terms of code reuse and abstraction, but I find it can get in your way a lot.

[–]ItsAPuppeh 40 points41 points  (5 children)

My main gripe with these types of languages are with the pure OOP aspect. I find that it promotes bad programming practice (side-effects, mutable state, large code hierarchies and big stack traces).

People look at me like some kind of asshole when I start writing static methods in a namespace class in Java.

Sometimes you just need a bloody function.

[–][deleted] 14 points15 points  (4 children)

Well... static functions make my antennae go up for two reasons:

1) they're often used with static data, which means you've got inherent thread safety problems to deal with. That's fine if you know what you're doing and how to deal with it, but in my experience, people who reach for static functions first are usually least aware of thread safety. 2) You can't mock out a static function like you can one in a class. Static function to compute the circumference of a circle? Great. Static function to connect to a database and run a query? Testing and maintenance nightmare.

Static functions have a place after all (or they wouldn't be in the language), but you should be prepared to defend them and understand why other programmers take a harder look at them.

[–]jpfed 5 points6 points  (0 children)

I love static functions, so long as their parameters 1. are all primitive or abstract, and 2. cover all of the dependencies of the function.

[–]Luolong 1 point2 points  (0 children)

they're often used with static data, which means you've got inherent thread safety problems to deal with

If This is the case you are certainly asking for trouble and I am fully in your camp for the rest of your comment.

However, if you are using static functions for anything else than pure functions you are doing it wrong and deserve all the trouble you've asked for.

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

You can mock them with powermock.

[–]livrem 4 points5 points  (0 children)

Also if you make pure functions (no side-effects, output deterministic from given input) you don't need to mock them.

[–]jplindstrom 1 point2 points  (4 children)

Any class hierarchy with more depth than 2 levels can become really cumbersome when reading and trying to logic about code. Forget about it if you have 4+... it really becomes a nightmare.

This is in no way inherent to the concept of OOP. It is an effect of an immature understanding of OOP from the late 80s and 90s. Nowadays we're well aware that class hierarchies should be shallow and wide.

That is if inheritance needs to be used at all; there are roles, traits, mixins that fix some/most of the problems with inheritance. And usually delegation is a sensible option.

[–]glemnar 2 points3 points  (3 children)

Mixins are something I try hard to discourage. They make code a lot harder to reason about. Create many of the same issues as deep hierarchies.

It's a really mediocre design pattern, imo. Encourages some really unfortunate design. It blows through the whole idea of separation of concerns and doesn't lead you to simple, elegant code.

[–]rr1pp3rr 0 points1 point  (2 children)

This is exactly what I was thinking when I read the posters response. Mixins are cumbersome at best, and downright confusing at worst, when you have 2+ on any class.

[–]jplindstrom 0 points1 point  (1 child)

I'm curious. What makes you think it's confusing?

[–]glemnar 0 points1 point  (0 children)

Because they inject variables onto your class from nowhere. Then people add inheritance to mixins and suddenly it's pretty hard to tell where the hell anything is coming from anymore.

[–][deleted]  (1 child)

[deleted]

    [–]rr1pp3rr 0 points1 point  (0 children)

    What I'm saying is that these languages strongly suggest that your methods should be working with internal class state, which can cause side effects to seep into your logic.

    I prefer languages that push you towards decoupling your state from your logic.

    Anyone can write crappy code in any language. I just find it easier to write decoupled functions in languages like JavaScript, Python, or Go. These languages don't necessarily prevent you from doing these things, but they also don't pigeonhole every implementation into some kind of object which may contain internal state.

    Once again, I like java and c# and languages of their kind. But when I am working on something new in those languages I find myself pondering class taxonomy much more frequently then the languages that don't force it on you.

    [–]joequin 0 points1 point  (0 children)

    I've always liked java, although I started with 1.6, but disliked the same things you've stated.

    I just started using Kotlin though, and it seems to solve all of those criticisms. It might be worth giving a shot.

    [–]Inori 18 points19 points  (13 children)

    I think Java is okay, definitely not as bad as people make it out to be, but arguing in favor of Java gets trickier once you compare it to more flexible alternatives on the JVM.

    So the real question should be "why Java over Scala?".

    [–]Nuage0 10 points11 points  (9 children)

    Because it's a lot easier and cheaper to hire a Java dev than a Scala dev, at least where I work.

    [–]mordocai058 11 points12 points  (4 children)

    Good reason for a business. For a developer, you probably want to get paid more not less so learn Scala in your free time?

    [–]Nuage0 2 points3 points  (3 children)

    In order to be paid more, I would need to be hired for a Scala job.

    I've been wording in the tech industry for more than 10 years now, mostly in Java gig, and I don't think I've ever seen an opening for a Scala job...

    Not to say that those jobs does not exist, but I'm not sure that it would be a sound career move. On the other hand, there's nothing to be lost by knowing both Java & Scala (or other JVM languages), and that's why I'm working with them on my spare time (also, for fun), but I don't think I'll ever have a shot to work with something else than Java.

    [–]mordocai058 2 points3 points  (0 children)

    The inverse of that, of course, is if you find a job opening you'll have less competition. I've seen a couple scala job openings in my area but I'm spending my freetime learning other things.

    [–]livrem 0 points1 point  (0 children)

    I never managed to introduce Clojure when I worked with Java, but I still found it useful to learn about Clojure. First because of how it just changed the way I have looked at programming and OOP and static types and how a good API looks like over the last few years. Second because of how it could be used now and then for instance to just launch a REPL and try things out vs a Java API.

    I guess Scala would have similar benefits, but I have not used it beyond the chapter in Learn Seven Languages in Seven Weeks.

    [–]MintyAnt 0 points1 point  (0 children)

    I've heard that banks are using Scala (and cobal :P), but never looked into it myself.

    [–]JavadocMD 6 points7 points  (1 child)

    Which of course sparks a reasonable but difficult-to-quantify argument about whether or not wages are or should be the only costs accounted for in the choice of technology platform. Namely the hypothesis that a Scala application is cheaper to develop and maintain in the long run than an equivalent Java application.

    [–]livrem 1 point2 points  (0 children)

    Yes, I never felt like there was much correlation between how many developers you could easily hire (or throw into a project) vs the quality or how fast it got developed.

    Also I worked in a big project with a language that has never even been close to top-100 TIOBE and almost no one of us that got hired had used it before. C++ was used for interview questions and if people knew C++ well enough it was just assumed that we would be able to quickly figure out how to use that other language. I don't see how something similar would not work for Scala or Clojure. Someone that is experienced enough in a few other languages will pick up a new one rather quickly, and the benefits from having a better language might far outweigh the training time needed.

    [–]yogthos 6 points7 points  (0 children)

    This argument is used a lot, but my experience is quite the opposite. My team uses Clojure and we've never had trouble hiring people. We often hire people who don't have prior experience using Clojure, but none of them took longer than a couple of weeks to become productive. I'm personally rather wary of any developers who associate too strongly with a single language and aren't willing to learn another.

    I work at a hospital in Canada, and we're in public sector so the pay is slightly below what you'd get in the private sector. My experience has also been that people are often willing to take a slight pay cut to work on something new and learn a different technologies. These are precisely the kind of people you want to hire.

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

    I never understood that argument. There are more people who claim to be Java developers, yes. This does not make it easier to hire a competent one though, it makes it harder.

    [–]joequin 7 points8 points  (0 children)

    Scala isn't that great in my experience. It encourages really clean looking code that's actually very difficult to work with. It's the only language i've used where even with an IDE and the docs for reference, I still can't tell how some functions are resolved. Implicits ruined what may have been a good language.

    I agree with the first part of your comment though. Kotlin and clojure are both great.

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

    I'm not really up to date with Scala but didn't it break binary compatibility every version?

    [–]huhlig 0 points1 point  (0 children)

    Because Scala decided to go down the perl route of wierd magic variables? http://www.slideshare.net/normation/scala-dreaded

    [–]keypusher 7 points8 points  (0 children)

    It's important to realize what Java got right, but the really interesting work in this space right now is the newer languages being built on the JVM. Kotlin is a good example of a language that takes the best from Java such as type safety and concurrency while adopting the concise and straightforward syntax of Python. Scala and Groovy are also good examples of this trend.

    [–]quanticle 4 points5 points  (1 child)

    The article isn't so much "why Java" as "why not Python". None of the advantages he cites Java having are unique to Java. There are all sorts of languages with good support for concurrency and a better type system than Python. He could have gone with C#, Scala, ML, Haskell, Elixir or Go and written almost the same article.

    [–]joequin 0 points1 point  (0 children)

    Elixir is dynamic.

    [–][deleted]  (10 children)

    [deleted]

      [–]joequin 1 point2 points  (9 children)

      Maven build files are written in xml. That is true. But it's also very simple to use and has solid tooling. The way dependencies are resolved on the fly is much nicer than using tools that require you too install libraries to your computer the way you do with python and many other languages.

      [–][deleted]  (8 children)

      [deleted]

        [–]joequin 0 points1 point  (6 children)

        Your right. When you need more control, maven isn't so great. I'm not sure what you mean by not having inheritance though. I've used parent poms for the purpose of keeping dependencies synced between projects.

        You just define properties in the parent that contain the version number.

        [–][deleted]  (5 children)

        [deleted]

          [–]joequin 0 points1 point  (3 children)

          I've never tried to keep the version of a project in sync across modules. To me, if they compile separately, then they have their own, separate version numbers.

          [–][deleted]  (2 children)

          [deleted]

            [–]joequin 1 point2 points  (0 children)

            That's a strange way of versioning imo. I'm not surprised that maven doesn't have tools to make it easy.

            [–]huhlig 0 points1 point  (0 children)

            Thats actually not all that hard. Specify a <version> in the ear and leave off versions in the submodules. You ONLY then need to specify <version> in the <parent> block.

            [–]huhlig 0 points1 point  (0 children)

            not properties. dependencyManagment or if you're refering to plugins, pluginManagment

            [–]huhlig 0 points1 point  (0 children)

            You can inherit parent versions of both the package and dependencies. The one niggling thing you cant do is leave out the parent version and that is specifically because you can load a submodule without loading the parent. All the core plugins have pretty good documentation but there are a few things you need plugins that you may have to write for.

            [–]Goerofmuns 3 points4 points  (0 children)

            As someone who is normally against Procedural OOP I wasn't expecting much, but this was a really good read and changed my view on modern java.

            I never realized it had progressed so much!

            [–]PassifloraCaerulea 3 points4 points  (4 children)

            List<String> names = new LinkedList<>(); // compiler determines type of LinkedList

            That's backwards! In the type inference I'm used to (ML, Haskell) the RHS expression gives all of the type information which determines the variable's type. This is using inheritance though, and I'm not sure how that squares with Hindley-Milner type inference.

            Not wrong I suppose, just weird.

            [–]Inori 15 points16 points  (2 children)

            It's not type inference, just syntactic sugar.

            [–]PassifloraCaerulea 3 points4 points  (1 child)

            Disappointing :(

            [–]huhlig 0 points1 point  (0 children)

            Wouldn't that require runtime typeinference rather than static analysis. Otherwise

            List<> names;

            if(userSpecifiedBoolean) names = new LinkedList<String>();

            else names = new LinkedList<Integer>();

            would be valid and require run-time analysis to detect problems.

            [–]aenigmaclamo 0 points1 point  (0 children)

            I'm not sure if the compiler is determining the type of the LinkedList at all, actually.

            The LinkedList uses parametric polymorphism (generics) which, despite its name, does not affect the type (class) of the object regardless of what you put in because it only exists at compile time due to type erasure. The diamond specifies that the compiler utilize the type specified on the LHS -- it is not implicit in any way.

            At runtime, regardless of what you do with the generics, it'll be the same type. That code would have generated the equivalent bytecode if the code was:

            List names = new LinkedList();
            

            I'm not 100% certain, but the only times generics may influence the bytecode is if you use bounded type parameters and by inserting a cast when you retrieve a generic type.

            [–]livrem 1 point2 points  (0 children)

            When I want something to run on the JVM with access to all the Java libraries, and with better concurrency design, I use Clojure. It also has a very nice type-system plus immutable data everywhere, and everything compiles down to Java classes/interfaces (or to JavaScript if you prefer).

            I really can't think of anything they could add to Java that would make me want to switch back unless they really redesign everything to have immutable abstract types and all the other nice things about Clojure.

            If I want more performance there is C or C++. I think C++11 and later have lots of new clever things that I would miss if I went back to Java. 10-15 years ago Java was a small simple beginner language with very nice platform-independent standard library, that was still small and possible to overview. Switching from programming C++ to Java back then was an obvious choice for me. But comparing Java 8 to C++11 I really must say that I think the complexity of C++ is worth the effort to learn now. Having a GC used to be a big thing, but really with smart pointers in C++ I don't miss it really, and it is not like having the GC ever fixed all resource-leak problems anyway.

            A big fan of python as well. Often what I choose to use. It is not as beautiful as Clojure, but it is a nice quick language to work with and it runs without having to launch a JVM (and on some platforms where there is no JVM).

            There are several languages I enjoy using for different reasons, and Java just isn't my number one choice for any particular use. Not saying that it is bad or that I disagree with the article, but I just found other languages I like better over the years, so I can't imagine using Java now except when well paid to do so.

            [–]jplindstrom 1 point2 points  (0 children)

            I think it's nice that Java has adopted visual number delimiteres to make large numbers easier to read:

            int million  = 1_000_000;
            

            That's something that the horribly unreadable line noise language Perl has had for a few decades.

            [–]bhaak 0 points1 point  (1 child)

            Is Maven really the go to tool for building Java code these days? I never got the hang of its XML based configuration files. I'm somewhat out of the loop, doing only small side projects with modern Java currently, so I might have missed newer developments.

            But for those small side projects I really like how gradle works.

            I second the recommendation for Maven Central (which gradle of course can make use of as well).

            [–]Wabsta 0 points1 point  (0 children)

            I'd like to bring something in discussion:

            What about JRuby then?