It may lack a lot of the fancier features of some newer languages but its still a very effective language.
It may lack a lot of the fancier features of some newer languages but its still a very effective language.
Coming from JavaScript, TypeScript, Python and Go back to Java I can tell you that’s actually a good thing.
Cleverness in code starts working against you as a code base and organizations scale.
What do you find magical in terms of Python in particular?
> What do you find magical in terms of Python in particular?
Lots of libraries are magical. SQLAlchemy, most of the data science libraries, even the standard library returns different types based on the values of inputs (e.g., open() returns a binary file or a text file depending on the string you pass into it). Additionally, people often go crazy with various dynamic typing features (rather than refactoring into a common interface, people will do a bunch of `if isinstance(...)`es all over the place. Similarly people tend to go crazy with metaclasses and so on. I could go on and on.
We have code like (stupid example)
something.map( {a, b, ...rest} => ({ ...rest, ...a, ...[b, c, d]}))
I know what it does and how it works, but I argue that's hard to understand if you haven't written it and know the context.My Python experience is limited to only a handful of projects, but I looked into meta classes at the beginning of learning Python and that was some crazy stuff.
What are some things thing you can do in Java with less code than in Javascript?
We also do not use XML to configure DI. Just add a annotation to a class and you can inject it automatically in any constructor without any additional config/annotations.
If this is too much "magic" for someone's taste, I will not argue even if I have a different view. But please do not make absolute statements based on a bad experience in some companies.
Modern Java and frameworks have evolved a lot in recent years.
I understand the need for DI, sometimes the order of instantiation is necessary but for everything else I get lost in the DI constructor injection stuff.
In a functional language you could use a reader or environment monad to abstract the dependencies, but you don’t have that ability in a language like Java (and it’s not worth torturing the language to do it because it’s not idiomatic). So DI in Java ends up constructor-injecting service dependencies and using the method parameters to declare data dependencies.
Edit: another benefit of DI is that it allows for multiple lifetime scopes beyond application and method call. Spring has request and transaction scopes, for instance. Managing all that in Java without DI is a nightmare.
Now, I can go ahead and make the concrete implementation dependent on configuration, e.g. by providing multiple implementations annotating them with a condition that is evaluated using the application configuration. I can also switch to a factory method that creates and sets up the concrete implementation for the interface, I have not to change any place in the application that is using that piece, though.
The same should be possible in Go with reflect and an IoC container, but I am not sure if there's a solid implementation for that out there.
"null checks are ugly and error handling is messy" are your opinions, not objective facts. I actually prefer Rust-like enums, but short of that, I think Go's error and nil handling seems quite a lot nicer in practice than Java's `Optional` facilities. Note that these are my opinions, and I'm not posing them as objective facts.
The rest of them I've been enthusiastic about for a few weeks until reality catches up with me and I realize what I am missing out on.
Another thing I'd like to see is opt-in null safety. The Optional type is a very good mechanism, but when every reference is potentially null, its ability to enhance language safety is limited.
Other than that, it has everything I want. And of course, the ecosystem, tooling, etc. is simply the best in class.
My personal preference is for ML-style languages, so Java will never be my true love. But as far as languages go, you can do much worse.
Even then we won't have fully reified generics, but some of the stuff they're doing with type projections is insane. I'm pretty sure it's going to be a game changer.
If we're considering other JVM languages, Scala and Clojure are also on the table.
foo{ bar=true, baz=true }
Additionally, Spring Boot exists and is lightweight and super easy to understand, jooQ is an ORM/query builder that makes Hibernate look like a toy (and it super simple).
Just because Java gets tainted by overengineering doesn't mean the language itself isn't simple.
Even using the built-in JDBC support is an option with modern Java, PreparedStatement and ResultSet implement AutoClosable, which means you can write code like this:
try (
final var rs = conn.prepareStatement("""
<SQL here>
""").executeQuery();
) {
while (rs.next()) {
// do your thing
}
} catch (SQLException e) {
// your code here
}
Which is just the standard library and no more verbose than most other frameworks.As for web frameworks, there's a million of them. Pick a non-magical one if you don't like magic.
Spring had good documentation that you can read on an ereader. It's also very mature, so there's lots of help on Stackoverflow.
Hibernate was a bit more difficult, but Vlad Mihalcea has improved the documentation side a lot.
Hibernate also allows you to drop down to native queries, which coupled with Spring Data's "projections" are useful.
Also, I think it is overblown how magical those annotations/code generation are. It is simply class path scanning and code generation under the hood, so that a proxy object is used instead of the interface. I would take this path any number of times instead of what abomination n developer hacked up over the years with no proper abstraction and documentation.