Hacker News new | past | comments | ask | show | jobs | submit login
Love It or Hate It, Java Continues to Evolve (azul.com)
143 points by nfrankel on June 17, 2019 | hide | past | favorite | 153 comments



In my experience most people don't like Java due to experiences they had before Java 8. This means they were used to the bloat, config as XML style world which made Java a pain to write and slow to run.

Once I show them Java 11 with var keyword, lambda's and streams they start appreciating how modern the language has become. Then you throw in frameworks like javalin or sparkjava and suddenly they are not as hostile as they were before.

Honestly the only things I would really like out of Java these days are data classes and possibly native runtime compilation out of the box. Containers solve the latter issue, but id love to just build a binary and run it.

Do that and its on the same level as Go in many ways which nailed the tooling and deployment model, even if the language has issues. Java already has the tooling.

I suppose a decent syntax highlighter library like pygments or chroma would be nice too.


Agreed on all points.

You mentioned Go, so I'd like to add that Project Loom is the OpenJDK initiative to add green threads/coroutines to the JVM which I'd love. The tricky thing with "data classes" are that everyone wants something similar but different between the various terms: records, data classes, value types.

Personally, what I want from this is essentially Lombock-style all-args constructors, equals, hashcode, and toString. Struct-like like embeddability and flat object-headerless arrays are cool but honestly more niche. I don't mind sucking it up and using unsafe.


Loom is rather nice, but frankly I don't find the lack of co-routines something I miss. You can spawn hundreds of real threads a second so it is possible to write Go style code in Java if you really want. I may change my mind when I actually use it though.

I don't mind what type of data classes they come up with. I just want to not have to write stupidly long constructors, multiple sets or chain-able objects when I want to populate some fields.


I've definitely had to fix servers that have choked themselves with thread abuse, so maybe it's ptsd. The fixes can be as simple as shrinking threadpools to needing substantial rewrites, so I still treat threads as resources requiring management.

Green threads are nice because they let me separate logical execution from operating system resources. Unlike Go, Java will expose the ability to use a custom scheduler, so that should be nice!

My personal pet usecase is actually the opposite. I want to isolate 5-10 "low priority" tasks to a single kernel thread to isolate how much damage misbehaving code can do.


You can already use custom schedulers with java.util.concurrent though.


Except that the memory overhead for each thread is MUCH higher: the default would be 1Mb for most JVM implementation.

Yes, you can change the thread stack size, but that's a global fixed size for all threads, so you can't make it to small, or you'll risk stack overflows.

Meanwhile, Go is using dynamically growing stacks, starting at 2k.


It doesn’t actually use 1mb. Only if the stack touches the pages will it ever allocate the physical memory. Most threads won’t use more than 16kB (the lower bound when I last tested it on x64). Still, it’s a lot larger than green threads.


Java already has both records/data classes[1] (including pattern matching) as well as value classes[2] in the works.

[1] https://cr.openjdk.java.net/~briangoetz/amber/datum.html

[2] https://openjdk.java.net/projects/valhalla/


The additions and improvements are great but I think we're developing a kind of shared 'Modern X' fallacy. Modern Perl, Modern C++, Modern PHP, Modern Java, etc. The 'modern' facilities and the styles and efficiencies they enable are invariably terrific but you can't comfortably and effectively make use of them without having to know the bulk all the non-modern stuff. Which ends up limiting the appeal to the sorts of people who were prepared to put up with pre-modern to begin with.


I agree with this to a large extent. A new codebase in the latest Java/whatever can be OK. But most of the time I feel like it's dealing with the same bad code, with just a smattering of nice syntax on top.

I started learning Perl in 2007; after it was no longer popular, but also around the time that the principles/practices that became 'Modern Perl' were becoming popular in the community.

I think there is a difference between the two though. Java was always a language which required a lot of ceremony and typing to get anything done at all. Perl was always focused on expressivity. Modern Perl was a case of learning from past mistakes and consciously avoiding some of the more egregious code the language easily afforded. Modern Java is more a case of Java playing catch-up to the more expressive languages out there.

One is applying constraints on your coding style, the other is trying to lift constraints. Both are trying to reach some middle point.

But! I agree that no company writes purely 'Modern Perl' - you will have to deal with some terrifying code at some point.

So. I agree with the concept of the 'Modern X' fallacy, but I would say that dealing with non-modern code is pretty normal, and people who are OK putting up with the pre-modern code may be some of your best employees. I suffer from rewrite-it-all syndrome myself sometimes, but it's something I try to avoid. Code that frustrates me, isn't necessarily bad.

(If it helps contextually, I'm - at heart - a Clojure programmer.)


I may work with java soon, so I was reading about Spring and it was yet again a dive into insane amount of verbose over engineering that I ran away from years ago.

It's true that post 8 Java becomes palatable. And someone on reddit just showed me this piece of stats:

https://www.jetbrains.com/lp/devecosystem-2019/java/

83% on java 8, java 11 nicely going up

I pity those forced to work with old techniques


I write quite a lot of Java, and I have to admit I never “got” Spring.

I’d much rather have explicit boilerplate code (preferably in library form as much as possible) than complex, invisible magic.

The latter is “easy”, but the former is “simple”. In most cases, “simple” is more important.


I'd say there is no upside for the complex invisible magic. Half the time you have to run the application and pray that the configuration beans you've placed are working and if not, you are pretty much in trouble. Perhaps you missed a step in adding a configuration decorator in your application or configuration class, or used some deprecated method or used some incorrect class in the class hierarchy for the bean you want to return.


it's not even magic, it's redundant over engineering at its peak

haskell has magic, but at least its concise..


It's like playing Where's Waldo, to find the actual code in an enterprise Java/C# application.

I think it's a fundamentally different mentality as far as the code. The codebase is so obfuscated that it might as well be binary data rather than plaintext files. You need an IDE to manipulate it efficiently.


I feel like Enterprise is all about looking complex to justify the fees. The simpler it looks the harder it is to bill.

http://jeffacubed.com/the-boilermaker-story-or-knowing-where...


But Spring gives you the best of both worlds. A lot of verbose code (as annotations and class inflation instead of explicit boilerplate) and inscrutable magic.


If only we could all agree on what "simple" means - a lot of "enterprise" code I've seen would sweep vast amounts of complexity into hard to spot places to that you could have a small thing that people could point at and say how simple the one visible bit was, ignoring the vast amount of complexity lurking under the surface somewhere and invoked by more or less magical means.


I disagree. The "boilerplate" is the boring stuff I don't want to waste my time with.


In my opinion software development is less about what specific developers want to spend their time on, and more about producing solid software.

Does not spending time on boilerplate improve the quality of software you produce? I find that it doesn't.


> I pity those forced to work with old techniques

java modules broke a lot of software that were using sun classes or did classloading magic.

I was on one of such application, it's not a lot of effort to migrate forward, but many of the issues are runtime only so unless you have a good test suite, a strong incentive and no closed source library that use some such classes you can't really move forward with it.

anyway, in java 7 was already possible to write "unbloated" code, especially with the servlet 3.0+ spec, but spring and osgi have a lot of inertia in the enterprise community, meaning most people were stuck programming in xml, one of the most unpleasant experience ever.


I wonder how much salary increase it would take to make working with xml/spring worth someone's while.

ps: also how many shops are doing 'migration off of spring' ?


I wonder how much salary increase it would take to make working with xml/spring worth someone's while.

Meh.. in my opinion a lot of this is just tropes. Spring is a fine environment to work in, although you really don't have to use any XML with modern Spring. But you can if you prefer to for some reason.

All the annotation driven "black magic" can be mildly annoying at times, especially before you understand what's going on under the hood... but considering the amount of boiler-plate crap it saves you from dealing with, I'll happily accept that tradeoff.

For my money, if I was starting a new backend service today, I'd absolutely reach for Spring Boot as my starting point. Of course, I may be biased given that I've been writing Java code for 20 years, and I remember what a breath of fresh air Spring was compared to the old EJB 2.x era "J2EE" stuff.


> old EJB 2.x era "J2EE"

could have had worse you started just around the xdoclet, that was peak madness


Some of us worked at a shop that embraced Microsoft’s “embrace and extend” J++ with COM wrappers to go with Java. I still think THAT was peak insanity.


I actually was around for the XDoclet era, although I managed to mostly avoid going down that particular rabbit-hole personally. I think I even have the Manning XDoclet in Action book still on a shelf somewhere around here. Never quite got around to reading it...


java: provider of fine screen stand since 1995


I accept your pity. All my code has to be JRE5 compatible...


Nice constraint..

is it allowed to produce libs in jars from non java languages ? Even though I don't think clojure/kotlin/else support jre5 out of the box anymore.


Big fan of sparkjava for no-nonsense HTTP services. The days of tomcat-for-everything were not fun as someone who only occasionally dabbled in java back then.

So I have to build this as a special type of jar and then set up this other, rather opaque, set of stuff and deal with all sorts of nonsense ...

Now?

  get("/hello", (a,b) -> "Hello World");
And we're done...


That sure looks nice, but how often do you write services which return a single constant string? I like to judge languages/frameworks based on more representative snippets.


I think this is not about showing off the easy case, but rather the straightforwardness of the framework. I haven't used spark myself, but I used frameworks quite like it (Jooby, Rapidoid, Ktor) in Java, as well their counterparts in Nodejs (Express, Koa) and Go ("net/http" + some router).

The applications certainly got a lot more complex than that, but we never found ourselves in need of a magic annotation that you can't step through with your debugger.

This is all about simplicity. It's pretty clear how a get() function on the router which takes a route and a callback works, but it requires some work to understand how Spring magically scans all your classes looking for annotations and then builds parser based on that. It's quite unclear where all of the routes are coming from (since they can come from a class just about anywhere). You suddenly need special tools. And the worst thing that suffers is transparency. Ctrl-clicking/Cmd-clicking on an annotation in your favourite IDE never tells you what it does.

In comparison, a second-order function is a vastly simpler and more grkoable beast.


> That sure looks nice, but how often do you write services which return a single constant string?

The point was just to show that the http server aspect of it is trivial to set up.

You can hook in whatever you want from there.


FYI, the "(a, b) -> Hello World" piece is a lambda returning a string constant, rather than just a string constant, hence the ability to hook in whatever you want.


In Scala using Cask it's

    object MinimalApplication extends cask.MainRoutes{
      @cask.get("/")
      def hello() = "Hello World!"
    
      initialize()
    }
API design shamelessly stolen from Python's Flask framework


Since we are hiding the rest of the app, in spring boot + kotlin that would be:

    @GetMapping("/hello") fun hello() = "Hello, World!"


That's a nice try, but the rest of the app would be[1]:

    import static spark.Spark.get;

    public class HelloWorld {
        public static void main(String[] args) {
            get("/hello", (req, res) -> "Hello World");
        }
    }

[1] http://sparkjava.com/


It is indeed a nice try, and the rest of the app would be:

    @SpringBootApplication
    @RestController
    class DemoApplication{
     @GetMapping("/hello") fun hello() = "Hello, World!"
    }

    fun main(args: Array<String>) {
     runApplication<DemoApplication>(*args)
    }
And this taught me that the best sinatra clone in java isn't really worth it in terms of lines of code saved (we save what? 3 lines of code? 6 with the imports?) when compared to a full-blown web framework like spring boot.

Would you care to do another one where we return a json response? I'd bet you will need a json mapper class for complex objects whereas I will return a dataclass instance and it will just work.


In Kotlin, so you don't have to define multiple files, obviously skipping the imports. Let's do the same with Jooby, for instance:

    fun main(args: Array<String>) = run(*args) {
      get { "Hello Kotlin" }
    }
It's always easy to make a framework lightweight. But there is no argument that Spring requires a lot of tedious boilerplate in Java (some of which can be avoided with Kotlin), and annotations which are hard to understand.

Lightweight frameworks don't really tell you "We do everything that Spring does in less lines", since at one point you'll ask them to make avocado toasts or something else that spring-bakery has a plugin for.

The real power of lightweight frameworks is their simplicity. This is not for everyone (that's why we've got Spring and Rails), but if everybody was fine with the tradeoffs that Spring makes, you'll see the same kind of frameworks ruling the Node.js and Go landscape.


I understand, and I used to be in the sinatra camp a decade ago. What I really disliked with spring/tapestry and rails was the (at the time) huge stack trace and memory usage.

The annotations I used were "this is a spring boot application" on top of a class and another which says "this is a rest controller" to start your hello world application and we only saved a few lines and introduced additional hidden complexity with sparkjava because we still don't have a way to handle json whereas it comes free with spring boot.

You've got another one that says "this is an injectable service" and another which says "this is a db entity" and with the "this is a configuration" you've got 99% of spring boot applications covered. Not sure what is so hard about the annotations. Maybe it has to do with "knowing more than just java/kotlin syntax" that puts people off?


I don't want to have to learn a brand new syntax to get things done.

Your Spring example immediately turns me off because it uses a bunch of annotations that could do pretty much anything (and I'd have to learn). Further, it uses kotlin which is not java - it's a valid choice but it's a more terse language in general (so not necessarily valid to compare against java examples).

Spark is straightforward and easy to read, it does one thing and it does it well, and it doesn't demand that I spend a lot of time thinking about anything other than what I'm trying to achieve. I have a lot of time for that.

For the record, with kotlin and skipping imports (of which there would only be one anyway) -

  fun main(args: Array<String>) {
      get("/hello") { req, res -> "Hello World" }
  }
I do indeed find this simpler than your proposal upthread.


Just now I embedded an amqp client into my app. To do that, I had to create a configuration class that instantiates necessary queues, exchanges and binds them to eachother using builder syntax and beans. The spring boot app lazily handles rmq client initialization and I didn't have to think of object lifetimes. That kinda sorta simplified my job. However, your point still stands, I had to learn new syntax (I learned to type @Bean) to do all this.


Nothing precludes you from using Guice or Koin for dependency injection with any framework. Yes, any DI framework would require you to understand some new syntax, but Spring again comes as more magical and mysterious, and the abstractions are always leaky. For instance, when using its magical scopes, it will create proxy instances without you using its magical request scope, bytecode-gen magic (cglib) or plain reflection (which is bound to be just amazing for performance).

This behavior which looks helpful at first glance, is very confusing. If your not proficient with Spring or spend hours reading the documentation you'll never understand that: 1. Your object lifetime is tied to the request. 2. The instance you see at the debugger is actually a subclass that redirects all call to the actual scoped object instance depending on a thread local variable (I guess?) 3. The proxy instance is either slow (JDK Proxy) or could cause you grief when you upgrade to the next version of Java (CGLIB). It's not clear which is which without some investigating.

I rather prefer to go with a lightweight framework + a sane DI framework and do something more explicit, e.g. create a RequestProvider<T> interface:

    interface RequestProvider<T> { 
      get(request: Request): T
    }

    class MyController() {
      val fooProvider: RequestProvider<Foo> by inject(name = "foo")

      fun myHandler(request: Request) {
          val requestScopedFoo = fooProvider.get(request)
      }
    }
This approach is more explicit, but I prefer it.


I don't get all this about Spring being an "insane" way to do DI. It works well enough, and Pivotal is very thorough with their documentation. I would much rather RTFM than dig randomly through the code and hope I find what I'm looking for.

How exactly does Guice differ in request- or session-scoped injections that makes it that much better?


> Just now I embedded an amqp client into my app.

I have no need for one of those, I'm good building some fairly simple microservices against spark without 'lazy client initialization' or any framework features.

That's kinda the point, it's a simpler toolset for a single purpose. You may have requirements that are made simpler for you by knowing the arcane ins and outs of a feature-rich framework.

Not everyone does, and bringing in said framework to achieve something simple in the name of "Maybe, in future, I may need this" is a prime route to an overcomplex, heavyweight mess. IMHO.

Maybe you've avoided Spring-related hell, but all the java devs I know who survived that era tend to groan whenever it's mentioned.


> Once I show them Java 11 with var keyword, lambda's and streams they start appreciating how modern the language has become.

I wrote a lot of Java, but it was a long time ago. Could you share a bit of code representative of the modern Java 11 style you mentioned (var keyword, lambdas, streams, etc.)?


Not the guy that you were asking but Trivial example:

  public static void assertIsSuperset(Collection<Object> superSet, Collection<Object> actualSet) {
    final List<Object> missing;
    missing = actualSet.stream().filter(x -> !superSet.contains(x)).collect(Collectors.toList());
    if (missing.size() != 0) {
     /* Imagine some more verbose exception creation here, which is why we caught it in a list*/
    }
  }
The lambda is in the creation of 'missing':

  filter(x -> !superSet.contains(x))
A lot collections in Java 8 brought in a stream method which has some functional esqe methods. Filter is one of them, and if you look at filter's method signature:

  public interface Stream<T> extends BaseStream<T, Stream<T>> {

    /**
     * Returns a stream consisting of the elements of this stream that match
     * the given predicate.
     *
     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
     * operation</a>.
     *
     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
     *                  <a href="package-summary.html#Statelessness">stateless</a>
     *                  predicate to apply to each element to determine if it
     *                  should be included
     * @return the new stream
     */
    Stream<T> filter(Predicate<? super T> predicate);
  [SNIP!]
  }
Predicate is an interface that has one method: 'public boolean test(T t);'. The lambda that I created conforms to that single method; accepting the generic object (x) and returning the boolean tested by '!superSet.contain(x)' The other way I've seen them used is to implement an anonymous version of an interface.


Thanks! I guess your example could be simplified further with the var keyword:

  public static void assertIsSuperset(Collection<Object> superSet, Collection<Object> actualSet) {
    var missing = actualSet.stream().filter(x -> !superSet.contains(x)).collect(Collectors.toList());
    if (missing.size() != 0) {
     /* Imagine some more verbose exception creation here, which is why we caught it in a list*/
    }
  }


That still seems very clunky and also very inefficient compared to what I'd do in Swift:

    func isSuperset<Type: Equatable>(superSet: Set<Type>, actualSet: Set<Type>) -> Bool {
        return actualSet.contains(where: { !superSet.contains($0) })
    }
What is all the noise about "collect"? Why allocate a while new list? What's with the "final"? And why do I have to type out obvious types in 2019?


Because you're doing something entirely different, I'm asserting, you're testing. The equivalent java code would be:

  return superSet.containsAll(actualSet);
But a straight up boolean doesn't tell me what is missing, only that something is missing. I snipped out the bit about creating a more verbose exception creation because it wasn't really needed for the example:

if (missing.size() != 0) { final StringBuilder builder; builder = new StringBuilder(); builder.append("Missing item found: [ "); builder.append(String.join(",", missing.stream().map(x -> x.toString())).collect(Collectors.toList()))); builder.append(" ]"); throw new IllegalStateException(builder.toString()); }

Keep in mind that the objects that this method was written for actually implement human readable toString methods.

> What's with the "final"?

Habit that I forced on myself. But it's not a bad habit to get into. In theory methods are supposed to be short and readable but reality often ends up being that in the fury of writing under looming deadlines you can have horrifically long methods that do many things. And I've seen more then a few times someone reusing variable names badly. Using final when possible is just a way for someone to be able to look at the code, see the variable name and be able to know that what it says is what it is.

>And why do I have to type out obvious types in 2019

Because types aren't always obvious. That's a list, meaning that you can have duplicated items and that order matters. What if my 'list' was actually a set, in which order was not guaranteed? What about if you're trying to integrate this with multiples teams scattered across the world that don't speak English on a code base that's about 500,000 lines of code? Or when you walk away for 2 or 3 years and then have to come back to a method that's not as small and trivial as the given example? What about the next poor sap that has it dumped in his lap?

I know it seems stupid in the short run, and if you've got something small or something that probably wont' be relevant in a year or two, and I'd agree with you if that's the case. But but if you've got a code base that needs to be communicated to other people, then typing is a good way of handling that communication without having to write extra documentation.


Except that is a Pyrrhic victory, as Swift is quite useless outside Apple platforms.

Linux support is still WIP, Windows nowhere to be seen, and everything else is not supported at all.


The equivalent expression in Java would actually be this:

actualSet.stream().anyMatch(x -> !superSet.contains(x));


Yeah, the collect isn't really needed, you could easily use a reduce to calculate the value.


I've not yet worked on anything more recent than 8 but ...

I have a Map of Lists of Foo items (foos), and I want to transform each item in the sublists to a Bar, filter out bad Bars, transform to Baz and keep the results as a new list of Bazs

  List<Baz> barList = foos.values()
                          .stream()
                          .flatMap(List::stream)
                          .map(Foo::transformToBar)
                          .filter(Bar::isBad)
                          .map(Baz::transformToBaz)
                          .collect(Collectors.toList());

The syntax is a little clunky at times... but once you get used to it it's quite expressive.


Java 11 is obviously much better than Java 8, which is still leaps and bounds ahed of Java 6, itself an improvement over Java 4. You'd see the same in every language.

Java's problem is that for many years it used to be the slowest car around. Maybe this was one of the things that helped Java become the undisputed ruler Enterprise Inc. but now it's got a lot to catch up with, and even though the pace has picked up since Java 9, it's far behind its competitors.

Everything you mention (var, lambdas, streams) and everything you might mention when Java 13 comes out (switch expressions, text blocks) is just too little, too late.

Yeah, var is a lifesaver if you have to use Java, but compare the limited type inference it brings to the table with almost any other competing language (Kotlin, C#, Scala or Swift) which at the very least can do a return value inference.

Likewise, streams are long due, but the syntax is horrible and the repertoire of built-in operations is meager, and since Java does not support extension functions like the rest of the languages mentioned here you can't extend them gracefully.

If you take one of the examples given here:

  var grades = school.students()
                 .stream()
                 .flatMap(student -> student.grades()
                    .stream()
                    .map(grade -> new NamedGrade(student.name(), student.grades())
                 .filter(x -> x.grade() > 60)
                 .collect(Collectors.toList());
Kotlin goes the same route, but makes it little more natural to use:

  val grades = school.students
                 .flatMap { (name, grades) -> grades.map {
                              NamedGrade(name, it) 
                  }}
                 .filter { it.grade() > 60 }
                 .toList()
Besides simply more natural syntax, get the special 'it' variable, destructuring, more operations and

Now take C#, a language had something "Streams" since version 3.0 (released 7 years before Java 8):

  var result = students
                  .SelectMany(student => student.Grades.Select(grade => new { Name = student.Name, Grade = grade }))
                  .Where(record => record.Grade > 60);
Where you get anonymous records - you don't need to define a new type anymore.

Or with LINQ:

  var result = from student in students select
      from grade in student.Grades 
      where grade > 60
      select new { Name = student.Name, Grade = grade };
You get a highly readable built-in query language as well.


Quick nitpick. Both of the C# examples are called LINQ. The first is called the "method syntax", the latter is called the "query syntax". The query syntax is transpiled into the method syntax before compilation.


The slowest car still gets you down to the city center.

And neither Java nor C# have anything to brag about Streams or LINQ.

I could already writen those code examples in Lisp, Scheme, Caml Light or Smalltalk.

What we have is mainstream computing catching up, or as Erik Meyer has stated, selling Haskell to VB programmers.


You have Clazz::someMethod in java so no need to write out the whole lambda expression


With kotlin, the final .toList() call can be removed


That sounds a lot like what people are saying about PHP and its newer versions. But the thing is, now that we have great alternatives (Kotlin, C#, Scala, Go, Dart...), what does Java have that those don't?


Millions and millions of people using them. High quality (and in many cases user friendly and familiar, too) tools built around them, several options, even.


A virtual machine backed by decades of development and millions of person-hours


This is not the only reason.

Who started using Java way before Java 8, used to experience serious issues about memory usage and performances in the JVM.

These memories struggle to leave.


Especially on 32-bit JVMs. Still have nightmares.


I can’t recommend sparkjava enough. It is the only Java web framework I’ve encountered whose “quick start guide” is actually that: a guide that gets you started in minutes, not days. The fully working “Hello world” app is 5 lines of code.

I built my profitable, bootstrapped B2B SaaS using sparkjava.

You can find sparkjava here: http://sparkjava.com/


I was checking out Spring recently. The hello-world sample turned me off at once [1]. It's so much more clunky than something equivalent in Python/Go/what have you.

[1]: https://spring.io/guides/gs/rest-service/


While I agree with you that Spring is clunky, if you're making a simple application I don't think anyone will recommend Spring.

Where Spring shines is enterprise. When you have 600k concurrent users it's just something I can trust. Other solutions can work too, but we value the stability.


RE native runtime compilation: have you had a look at GraalVM's native image: https://www.graalvm.org/docs/reference-manual/aot-compilatio...


GraalVM works with Java 8, Java 11 isn't fully implemented


I think it is certainly part of it. I also don't like Java because best practices include hiding everything inside objects and developers are generally against using simple functions. I also dislike how leaky abstractions are common in average Java code and the unnecessary verbosity. Java 8 helped with many of these yet, it is uncommon to see Java 8 syntax in most sources I work with. Many large companies just migrated or in the middle of migration to Java 8.


Javalin is a bit of a cop out because it's not strictly Java.

I agree with modern Java improvements for the most part, especially if you are including Kotlin in that ecosystem - I really enjoy writing Kotlin.

However, I've professionally switched to Go and really wouldn't want to go back to Java much. I already think Go is a bit bloated, and I still feel like Java (even w/ the latest modern features) still gets incredibly bloated.


> I suppose a decent syntax highlighter library like pygments or chroma would be nice too.

Could you clarify this? I last worked on Java in 2016 but even at the time, we had eclipse settings that had Syntax highlighters. Am I missing something?


Have a look at http://pygments.org/ or https://github.com/alecthomas/chroma where you can pass code into a library and it returns highlighted HTML.

You can use Pygments in Java using Jython but its performance is questionable and can be incredibly slow when highlighting lisp code for example.

Its a very edge case for most people, but seeing as I am working on a searchcode.com upgrade I need a fast highlighter. Currently I am spawning a background Go process using Chroma to take care of this for me, but if there was a decent Java library I would use it. None exist I am aware of that are even slightly up-to date.


Like with C++ though, chances are you will not be working on a "modern" project and will have to deal with patterns like random nulls, APIs based on extending framework classes etc


problem isn't that stuff, it is how java is engineered, it was made for the 80's

gaming industry is huge, but you can't with java because autoboxing everywhere, no value type, and no specialized generics

same for serverless, you can't because you have to ship heavy runtime

same for machinelearning, you can't do math because lack of value type

etc etc etc

Java tried to fix all problems, but they forgot the essential stuff, performance and efficiency


check out what 'auto' does from C++11 onwards then, oh and smart pointers too: memory management is no hell anymore


did you ever try Kotlin ? whats your opinion there ?


I have not. The only major thing I see in Kotlin over Java right now (I don't do Android development) is data classes. Everything else is either in the language or should be soon which makes me hesitant to invest the time learning it.


I agree with you here, I think that Kotlin is settled for life in what concerns Android, given the sore state of Android J++ and #KotlinFirst announced at IO.

Outside Android, we can enjoy modern Java, which makes Kotlin just yet another language capable of targeting the JVM.


I find the Java love/hate intriguing, I personally like the ideal of 'getting the job done'.

Pre Java 8 is just fine, I don't think it's materially changed, I think what has changed is perception i.e. the realization that all that Enterprisy cruft 'does not equal' Java - nor do wee need FactoryFactor patterns.

My wishlist: - Stream syntax was nice, but a little clumsy - In addition to data objects, some kind of 'un-typed' object (better than a Map) for dealing with json-ish type data, right in the syntax. - First class functions instead of lambdas - Async notation as a better way to express threads, or even combining within the same thread - Union types

For compilation, you should check out Graalvm, which has some neat new features there.


> Async notation as a better way to express threads

CompletableFutures?

You don't deal directly with threads in java (unless you want to) these days.


I think the reason so many people have mixed feelings about Java is that "Java" is actually several things:

- The Java language

- The Java API (and/or whatever set of libraries you're using)

- The Java ecosystem, tooling, etc.

- The sorts of work typically done these days with Java

It's perfectly possible for one person to feel strongly one way about some of those aspects while feeling strongly the other way about others.

For instance, I'm quite fond of the Java language, I mildly dislike the Java API (in how bloated it's become), I'm ambivalent about the ecosystem, and I do my best to avoid the "Enterprise Software" CRUD-churn that Java development often entails (although this might have changed, it's been a while since I did Java commercially.)


Not a die hard java/go-or-anything entusiast, but replace the name Java with Go and you have the exact same thing.


But with Go you can iterate quickly compared to java as the compilation time is very small. This difference is massive in big projects. This is an important reason why I took up Go for many projects.


Can you give a few numbers what counts as "very small" here? Most of my big java projects take less than two minutes for a full compile and incremental compile of the whole project is usually in the range of 10 secs. If you run the whole test suite it can take longer depending on the tests, but that's not what I'd count as "compile time".


> "Enterprise Software" CRUD-churn

I did some Java in the late 90s at university, and a tiny bit in about 2001, pre-dating a lot of the enterprise stuff.

I've come back to it in the last three or four years and it's currently my main language. I think I manage to miss the enterprisey stuff. I remember J2EE happening to other people, and then for a while everything was Spring. Somehwere in there were 'Beans'

Now ... I was pleasantly surprised to come back to it. There are a lot of building blocks and interfaces to use in the various maven-centric public repositories, development is rapid, expressive (I <3 lambdas, which I never thought I'd say) and ... yeah. I'm having fun.

Part of this might be because I did (mostly) C for a decade!


If you have a strong background in both C and Java, I’d encourage you to give Go a fair shot. I also had long runs with C and Java, but ever since I’ve tried Go, it has become my favorite Swiss Army knife. Basically, it’s my default language until I have a reason not to use it.


Yeah thanks - I've been meaning to give it a go, but my personal coding time tends to be taken up more by "I want to do this" than "I want to explore this" and I haven't had the chance to use Go professionally yet.

Go and Rust are definitely on the list of things I want to learn though.


There's also: The java thing you have to install before using a desktop app that is somehow still incredibly slow and laggy even though you have a top of the line computer in 2019. At least that's been my latest experience with Oracle SQL Developer (glorified text editor), despite 20 years and eleventy bajillion dollars invested in the JVM, java is still a terrible option for the desktop.


My biggest issue with Java isn’t even the language, it’s the culture. I feel like typical Java solutions are just layers upon layers upon layers upon layers of abstractions, frameworks inside of frameworks, and stack traces taller than skyscrapers. It’s just too much!

It seems like the Java community has lost the art of coding without a framework. It feels incredibly bloated and entirely too magical. But this has more to do with the ecosystem and philosophies of the community, rather than the language, or even runtime, itself. From a purely language and runtime perspective, I think it’s fine.

But I don’t enjoy it. Every time I need to work on a Java project, it’s like it’s a form of punishment. I’d rather do basically anything else.


It's interesting how differently developers respond to languages and their ecosystems. While I don't love Java, i think it's fine. The documentation is very good and interoperability is excellent. Far from a punishment.

Punishment for me is PL/SQL which, despite its charming Pascal-like syntax, is painful to work with due to the lack of good tooling and it's awkward constructs (string handling, exceptions, etc.)

Honestly, despite its popularity, I feel the same way about Python. Working in Python on anything larger than simple scripts is difficult due to the packaging mess, the 2/3 issue, it's sometimes unintuitive idioms (think "".join(...)). Ruby is probably the most pleasant ecosystem I've worked with but I find dynamic typing a challenge on large projects. Point being, if I were starting a project in a corporate environment, Java (or at least the JVM) would be my default choice. Java seems to occupy a space where it's good enough or "least offensive" to the majority of the team.


I never really understood this argument, maybe I have something else in mind when talking about abstractions.

For example, even though passing a function to an SQS listener is many abstractions away from handling internet traffic from SQS, I'd much rather the parsing of bytes be hidden in a place where I never have to see it and I can focus on business logic that actually provides value.


To me you're talking about the java of a few years ago. It's really not the case now.

The enterprise-y types are no longer dominant in the space.


But the Java of a few years ago will still need to be maintained for many years to come.


Maybe so, but that's not a job I'm interested in :)


Stack Overflow yearly survey[1] mentions that ~40+% developers who took the survey use Java. Not very surprising if you look at how long ago Java came into being (24 years ago!). I, for one am happy that it continues to evolve. At the very least it shows that the developers of the language are still taking lessons from the programming languages ecosystem :-)

[1]https://insights.stackoverflow.com/survey/2019#most-popular-...


Java 8 made it an "okay" language for me to use.

It's a lot better nowadays, but historically the biggest problem with Java has been the 3rd party libraries. They tended to be written with extensibility in mind at the expense of usability. Extensibility is great, but it's not the only important thing in a design.

I'm not a huge fan of annotations. It makes the language feel a bit magical and hard to debug in some places. It can be difficult to track down how a given library actually treats an annotation - or even a set of annotations since you can put more than one on a given thing. It puts the language in a strange place: sometimes both boilerplate-heavy and magical.

> The introduction of annotations in JDK 5 has made enterprise Java development a whole lot simpler by allowing things like dependency injection.

This is a bit weird - you don't need annotations to do dependency injection. And you don't need a DI framework either. One thing I don't quite understand is the infatuation with DI frameworks in Javaland. I prefer to just do it by hand where both necessary and plausible.


99% of the time I see DI used in Java it is solely to enable mocked dependencies in unit testing rather than injecting different production implementations depending on environmental differences or something like that.

I have had Code Reviews where "This is all good, but you should use Guice to mock X" where X is the one time I might have a package-private test only constructor with a NullObject for the one dependency I need to mock out in a commit and Guice is not currently used in the package at all.

Personally I think DI has reached cargo cult status in Javaland.


Dynamic languages like Python do not have this issue as you can mock any method runtime for the duration of test. This can done via "monkey patching". It is unclean, but the development cost of having a framework to do just this is a tad high.

The only downside is that if you parallel test you need to run them in separate processes (which you usually want to do.any case).


You're right. Java is a decent language with a decent type system (bar the lack of null safety and some other quirks). It's all the annotations and reflection and XML and magic that creates most of the pain, and that's the fault of the library and framework developers, not Java itself.


> Java is a decent language with a decent type system (bar the lack of null safety and some other quirks).

Optional is your (and my) friend. It has a small performance penalty and for historic reasons it will never be used everywhere, but for new externally visible code (code not in the class) I try to use it and it makes for face nicer APIs.

I never understood why XML config everywhere and "we should configure it all instead of programming it" took off. You shouldn't change things on production anyway, so the main aspect "you can change it without recompile" is moot and instead you have all the downsides of not having part of your code checked by the compiler.


My only problem with Java is how it’s written. Enterprise java tends to be abstracted to absurd levels. I prefer a more direct approach.


Yes @ absurd level of abstraction, EnterpriseFizzBuzz even manages to laugh at this old-school 'Enterprise' style of writing code[1].

Some enterprises have managed to move away from this though -- DevOps in the enterprise is real and it looks pretty similar to DevOps elsewhere.

I've worked with teams in very conservative enterprises that have automated tests and CD pipelines, and release 100s of times a day, and support their own code. And with their newfound autonomy -- no more diktats about "use J2EE" from up top -- these developers did what smart developers do: simplify and reduce dependencies and tech debt. Lots of vanilla JS (or maybe React at most), plain old Java, even Kotlin and Clojure where possible (microservices made polyglot development really easy).

I've always thought this was a big reason Oracle dropped J2EE. Their most conservative customers weren't interested as J2EE had become irrelevant for their needs.

Here's a public video of how one institution (JP Morgan) managed to modernize[2].

[1] https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpris...

[2] https://www.youtube.com/watch?v=Tyev4Ti9Xsc


I love the fact that EnterpriseFizzBuzz has 271 open issues!


A lot of modern Java libraries and frameworks got better, and the Java standard library itself is moving away from deep class hierarchies, but I think there's a long standing culture that dictates how Java is "ought to be written" and it's quite hard to dispel that.

A lot of this is the language's fault though. For the sake of "simplicity" Java decided to:

1. Have a bifurcated type system with boxing, so a lot of generic code had to be obtuse or use a lot of reflection (It took a long time before Java added a very flawed generics implementation and convenience functions like Strings.valueOf()). 2. Disallow standalone functions (everything has to be a method on a class). 3. Implement many standard library APIs as abstract classes (and worse - concrete non-final classes) instead of interfaces, encouraging developers to overuse inheritance where composition should suffice. 4. Not provide any mechanism for delegating to member objects. 5. Encourage the practice of getters and setters, but provide no mechanism for properties. 6. Provide neither powerful meta-programming mechanism nor a strong type system, but create a powerful reflection API instead. Any surprise it will be misused?


Nothing stopping you from doing that. For HTTP some of the newer frameworks like javalin or spark encourage it and get close to flask or Go levels of simplicity. Chose you own JSON parser, connection pool etc...


As a fan of Java I absolutely agree. Having worked with python and C codebases as well, I think every language has its own particular "degraded mess" version. A sublanguage of hacks built up over years of deadlines, inconsistent bugfixes and evolving paradigms.

One nice thing about Java (compared to C and python at least) is that you have quite a bit more tools to refactor and despegettify codebases incrementally.


Most poorly written java project I saw was incredibly poorly abstracted, it was basically maps with strings as keys and values all over the place.


All programming languages when used at enterprise level suffer the same fate, I have enjoyed Enterprise C, C++, Clipper, .NET, Java, JavaScript, bash, zsh...


I'd like to see a JVM with a garbage collector that isn't designed to always consume the maximum amount of memory before it starts collecting. If you configure the JVM to have at most 400MB and it's current heap size is 120MB and you allocate 0.5MB every second or simply allocate 400MB of temporary objects that could be collected right away, it will allocate more GC heap until it hits the maximum 400MB and only then it decides to start a collection cycle. This makes the JVM useless for anything that isn't a web server that uses the entire RAM anyway.

Although Shenandoah looks promising but it's pretty telling that even in 2019 the JVM only has a single good garbage collector and it's still experimental. 23 years of history my ass. Other than the awful JEE ecosystem, the JVM is probably the worst part about the Java ecosystem. You can't fix it with a language that runs on top of it. It's slow (mostly startup performance), the GC is awful and it gobbles up a huge amount of memory. Obviously my company doesn't care because 8GB of RAM for a webserver costs them almost nothing.

It wouldn't surprise me if a WebASM implementation will take over one day, because the JVM is such a failure.


The JVM has state of the art GCs, name another platform that comes close in terms of offering the ability to tune it for throughput or latency as the JVM does, or that comes close in performance (.NET probably is the only contender).

If you don't want memory usage to go up to 400MB, then you can set the maximum memory the JVM can use to less than 400MB. It only makes sense from an efficiency and throughput standpoint to use as much memory available for performance.

JVMs regularly run on GBs or even TBs of heap space in production.

Both Shenandoah and ZGC target lower pause times (at the expense of throughput, naturally). There are commercial offerings like offerings from Azul that target low pause times as well.

> the JVM is probably the worst part about the Java ecosystem

On the contrary, the amount of optimizations that the JVM performs, as well as the monitoring, management, hotswapping, etc capabilities are second to none.

> It's slow

The fact that the JVM tops several charts here says otherwise: https://www.techempower.com/benchmarks/#section=data-r17&hw=...

> (mostly startup performance)

This is already being resolved through GraalVM. See for example https://quarkus.io/

> because the JVM is such a failure.

It only runs the backends of companies like Amazon, Google, FB, EA, LinkedIn, Ebay, Apple, Netflix, and countless others. Not to mention it's being used in high performance spaces like HFT.


I don't think any of your description about how the JVM GC works is accurate. The default GC is generational so it generally does lots of garbage collection before it takes up the reaches the heap limit. I assume what you really want is for the Java heap to return memory to the OS. The default JVM GC isn't configured to do that but you can easily configure the JVM to do that.

> JVM is such a failure

I'm genuinely confused why you would consider that to be the case. Especially since your preferred alternative (WebASM) is just about as bad or worse by your stated measures (start up time, GC).


I'm not sure what your real world experience with Java is, but GC is actually quite good and in server side Java I had no issues for years. G1 evolves and I had no issues with it. In Java 12 there is ZGC that have similar goals as Shenandoah, too. It is not like Shenandoah is something that is intended to be mainstream in Java. While G1 is optimized for throughput, Shenandoah is sacrificing performance for very short stop-the-world phase. It really depends on your requirement which one is better. There were multiple GCs before and alternative vendors have their own, for sure. What is your current pick and why is it so much better?

JVM is really good tech, it allows ecosystems like Scala, Kotlin, Clojure etc to exist. Since Java 8 there is class data sharing that may reduce your startup time and memory requirements a lot, especialy if you run multiple instances with same classes on same server.

Java ahead of time compilation was experimental since Java 9 and GraalVM should also help a lot if startup time is critical.


And, of course, even G1 does not fill all memory before it starts collecting. Even generational GCs before G1 divide memory into smaller areas and try to collect garbage quickly to get rid of short lived objects, so we're speaking about Java 6 timeframe. Example from my real world server - most of objects are collected at young generation, so gc costs are minimal, very few objects get promoted to old generation and full GC runs are very sporadic (and they are sub 1sec).


The only reason I like Java is that it allows you to sneak in Clojure code.

“I’m going to build a solution that runs on the JVM”


I made Clojure a first class citizen at my startup :)


Most people don't even know why they hate Java. And the rest hates it because their Chief Architect taught J2EE is a great idea.


Personally I developed a dislike for it because of Eclipse, Android Studio, Swing and JavaDoc.


Those are at the top of my list as well... in addition to Hibernate. Maven appears near the top of my list too, I mean can we please chill out with the copious XML already? Not to mention naming a real construct a "bean" rather than something that actually describes what it is, annotations and other magical shit (AOP anyone?) scattered throughout many Java codebases.


When I first went to college for my Associate's Degree, we learned C++ and had the option to choose between Java and Visual Basic. I chose Java, obviously, because who the hell wants to know Visual Basic?

I really liked Java back then because C++ had always been a struggle, not because of pointers or anything like that... but because I always found project management, figuring out how to link libraries, and build my projects, to be overly complicated. With Java, I only had to import a library, and that was it. I didn't need to link external libraries because Java's standard library was large enough that it had most of what I needed at the time, and adding external libraries wasn't nearly as difficult as C++.

However, over the years, I feel like I've kind of grown apart from it and have started to want to migrate back towards C++ and Python. I still use Java because it's the language I know best and it's the language I'm writing my game in, but after I finish my game, I think I'll be using it significantly less. The bulkiness of the code, the complications from the JVM, and the lack of good options for deploying executable code is just getting more and more frustrating.

Also, as I was working on my Bachelor's Degree, filling in the gaps of knowledge left by a "meh" education at my previous school, I could see that Java is just not good for writing good, fast code.

That said, Java 8 did make me like Java a lot more when it came out, but they're starting to deploy new versions so frequently now I feel like 8 is the last version I will bother learning.


> and the lack of good options for deploying executable code

GraalVM is a way to resolve that: https://quarkus.io/, https://micronaut.io/

You might want to check out C# as well. .NET Core is coming along nicely, and you get to work in a safe environment, with the ability to drop down to pointers if needed, unlike the unsafety that is inherent to C++.

There is also a C# to C++ compiler that the Unity people wrote, worth checking out.


Only a person who loves something would start with "Love it or Hate it", FYI.


"James Gosling, the Father of Java, described it as a Blue collar programming language."

I wonder what can be considered a white collar programming language which is actually used a lot. Erlang? ES6 with ever changing front end frameworks?


Python or Ruby I'd say, Erlang's a little bit too unique I think for that analogy


Python/Ruby are even easier than Java and don't require much skill to master.


I both love and hate it. I love the high quality libraries and ecosystem, reasonable performance, simple semantics. I hate the annotations and reflection magic, bloated frameworks, type erasure, lack of null safety, build systems. Luckily, it is possible to avoid some of that by not jumping on the bandwagon's standard stack. Leave that framework on the shelf, and Just Write Java. Unfortunately, many existing Java projects you come across in the wild are trainwrecks.


Which lib/framework to use today for a webapp backend development in Java ?

(I am senior dev, some past java7/8 core server experience, FE will probably be React and then mobile)


Vert.x + RxJava is great :)


What kept me away from Java was mostly configuration rather than language itself. You had to manually place jars in some lib folder, have things like "classpaths" and lot of this shit was glued together using XML files.

But once gradle came into picture along with IntelliJ I totally moved to Java.


One thing I would really love to see is a better way how you manipulate strings. Variable interpolation would be nice and you wouldn't have to have all that ugly string concatenation all over the place.


Don't forget regular expressions. How anyone puts up with having to escape all backlashes is beyond me. But, then, I'm used to Perl and Ruby. Scala, Clojure and Kotlin don't have this problem so why is the Emperor Without Clothes That Is Java having such a hard time?


Because it's 20+ years old and tries to be as source compatible as possible?


Perl and Ruby are at least as old but I never had to backslash everything when writing regexen in Perl or Ruby.


There has been about a 7 year window of opportunity for Oracle to really push JavaFX as cross platform UI, but they insisted on making it hard to legally use even for desperate Java Swing developer. Almost every Java Swing shop I know is either still on Swing, switched to .NET or switched to web shit.

Why, why, why did they not make JavaFX on Android a first class citizen?


You have to ask Google why, not Oracle.

Oracle has made JavaFX open source and available to everyone that wishes to work on it.

https://openjfx.io/

https://openjdk.java.net/projects/openjfx/

https://gluonhq.com/products/mobile/javafxports/

Naturally Google prefers to push Android J++.


I love Java, it's awesome language!


Why are the links larger than the body text on mobile? It’s so annoying trying to read this whole article. Especially when one of the links is pushing their commercial support of Java.

Good design and java rarely go hand in hand. These small details matter. I don’t think it’s a mistake that Ruby, JS, Rust, Elixir, etc attract people with good design sensibilities which is reflected in their blog posts, websites, and also API designs, documentation, etc.

But otherwise this articles content is not bad, I think we all know why Java and C++ are so popular. It’s one of the first questions every programmer learns their first year programming. This article is a good summary of why. The fact both C++ and Java got things like Lambdas and other modern stuff in recent years is great, but they are obviously incredibly late to the game. Which makes you wonder how long until the other good things will take. Maybe that whole backwards compatibility with decades of some questionable code being a dead weight dragging down the language is one of the reasons why people hate it? You can repaint a broken down house but that doesn’t mean it’s as good as the new house next door.


Any language that will survive as much as Java or C++ will accumulate some baggage, even your cool shine new language will look outdated 20 years from now to the new cool programmers.

Look at other examples, CSS - full of bad examples on how do do X, JS - a lot of bad parts, missing core stuff like importing modules , Python - it had is issue caused by some old decisions that caused a lot of pain when migrating version 3.

My point a 5 old years new language will eventually have similar issue in 10-15 years


The point is to work at the sweetspot of emerging language/high pay and then get out once the framework decision level bugs start emerging.

Then come back as a consultant in 20 years at the intersection of high pay/no one else can figure out how to fix the software.

If you're working with Java you're mostly in medium pay/tearing hair out coz of legacy issues-which you WILL have because a Java shop never COMPLETELY moves to the new thing. Not a fun place to be.


>If you're working with Java you're mostly in medium pay/tearing hair out coz of legacy issues-which you WILL have because a Java shop never COMPLETELY moves to the new thing. Not a fun place to be.

I am working in the present on Web tech, SPAs, but you know what, it sucks even if is the cool thin, the project was started with angular1 which is no longer the cool thing, it uses ES5 and gulp(no longer the cool thing), the backend uses Silex(a PHP framework that is not that cool) ...

The only cool thing I assume is to start new project in the this month cool shit and then after 1 year move to the new shiny and let people like me maintain your inexperienced code in the experimental shiny thing of last years.


Except that Java is that 20 year old thing, and it has stood the test of time, it's not the new COBOL.

I learned vi about 30 years ago, Java and SQL over 20 years ago, and they're tools I can still use every day to get stuff done.


Meanwhile people are porting old features from Java into newer languages. I say newer and not more modern because it's yet to be clear that many of the new shiny languages aren't actually ahead of the game in some areas but behind in others. Maturity of their ecosystems will be a good tell down the line.


Which features do you have in mind?


Generics in Go, JavaScript class/private members, both sorting modules/dependencies are things that come to my mind.


It’s not the language that is the problem. It’s more to do with just how many people use Java, and it being so ubiquitous results greater numbers of poor quality coders. Lesser known/adopted languages tend to be picked up by those who are already good at developing and designing.


Whilst I agree, it's language features are meant to reduce some of those issues. The rope you have to hang yourself with is a bit shorter than you have in other languages. At least in theory.


In practice, the language gives you enough rope if you don't think or care about design at all. This is a typical beginner's problem once they get past their first toy programs and try to write something useful.


I agree. Things like type saftey, interfaces, protected methods and properties and so on are what I was referring to. These kinds of features are borne out of necessity from big code bases and big teams, where you can't trust that every line of code will be written to the software architectures guidelines.

It shouldn't be possible for a new hire to feed a Customer to a Product repository for example, and in most mature languages we've made language level features to doo that, so we don't have to manually code checks in everywhere.

Eventually NewLanguage shows up without type saftey and everything is going great as it gets used in smaller projects. But then big teams start picking it up and suddenly these things are issues again.


> Java got things like Lambdas and other modern stuff in recent years is great, but they are obviously incredibly late to the game. Which makes you wonder how long until the other good things will take.

I see it all the time and I always found this sentiment incredibly bizarre. It seemed to presuppose that there is language ranking that is just a matter of feature check boxes, or that the introduction of a feature is some sort of admission that it should have been there all along. I hear it leveled at Go in particular but Java as well.

I can't speak for C++, but at least in terms of the Java-the-language most of us would rather see a language feature absent rather than done poorly.

It's not just a matter of borrowing from other languages. Each language's features have particular interactions with one another.

There are a thousand ways that Java's lambdas or var could have been introduced poorly. Go has shown that there's definitely an audience for more austerity in language design.


> Java got things like Lambdas and other modern stuff in recent years is great

These feel incredibly bolted on. Instead of a utilitarian, if verbose, lowest common denominator type of language, Java is becoming a Frankenstein monster. And a verbose one at that.


> Good design and java rarely go hand in hand. These small details matter. I don’t think it’s a mistake that Ruby, JS, Rust, Elixir, etc attract people with good design sensibilities which is reflected in their blog posts, websites, and also API designs, documentation, etc.

That's an interesting claim, but now that I think about it, I wholeheartedly agree. The reason for that might be Java's poor support for UI programming (especially on the web) and the coders therefore creating their blogs with alternative languages and ecosystems that they are unfamiliar with.


So only HTML/CSS programmers are decent at design? Honestly I see a lot of bad practices in Web, like using Divs for buttons when you could have use the button element(maybe there are exceptions but not in the cases I seen)


problem is it evolves way to slow that alternatives already emerged and are used by a lot of people who were looking for alternatives

so yeah, evolving in an empty ocean




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: