Live data from Hacker News

Love It or Hate It, Java Continues to Evolve

azul.com

111–120 of 156 posts

Re: Love It or Hate It, Java Continues to Evolve

#111

Earlier quoted context omitted.

Not the guy that you were asking but Trivial example: public static void assertIsSuperset(Collection superSet, Collection actualSet) { final List 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': filt…

That still seems very clunky and also very inefficient compared to what I'd do in Swift: func isSuperset (superSet: Set , actualSet: Set ) -> 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?

The equivalent expression in Java would actually be this:

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

Re: Love It or Hate It, Java Continues to Evolve

#112

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 supp…

I love the fact that EnterpriseFizzBuzz has 271 open issues!

Re: Love It or Hate It, Java Continues to Evolve

#113
post #94

Earlier quoted context omitted.

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 rea…

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…

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 interface:

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

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

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

Re: Love It or Hate It, Java Continues to Evolve

#114

Earlier quoted context omitted.

> 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,…

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.

Re: Love It or Hate It, Java Continues to Evolve

#115
post #34

Earlier quoted context omitted.

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.

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.

Re: Love It or Hate It, Java Continues to Evolve

#116

Earlier quoted context omitted.

Not the guy that you were asking but Trivial example: public static void assertIsSuperset(Collection superSet, Collection actualSet) { final List 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': filt…

That still seems very clunky and also very inefficient compared to what I'd do in Swift: func isSuperset (superSet: Set , actualSet: Set ) -> 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.

Re: Love It or Hate It, Java Continues to Evolve

#117

Earlier quoted context omitted.

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 g…

> old EJB 2.x era "J2EE"

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

Re: Love It or Hate It, Java Continues to Evolve

#118

Earlier quoted context omitted.

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 g…

> old EJB 2.x era "J2EE" could have had worse you started just around the xdoclet, that was peak madness

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...

Re: Love It or Hate It, Java Continues to Evolve

#119

Earlier quoted context omitted.

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…

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 reflec…

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?

Post reply on HN