I also generally am writing REST APIs and doing simple "enterprisey" stuff.
I also generally am writing REST APIs and doing simple "enterprisey" stuff.
Raw Java is Pretty Close to being "out of the box" OK for "REST, enterprisey" stuff.
The built in HTTP server is usable and functional. Of course TLS is built in. JDBC is built in (need a driver). While XML is built in, JSON is not. Logging is built in. JMX for monitoring is built in (lots of things can talk to JMX).
Are these all "top tier" feature rich implementations? No. But they're completely usable. With some thin veneers you can make them richer and more friendly. I've been using my own trivial Logger wrapper for years (mostly to support varargs).
If you're willing to take a bit of a step, JAX-RS on Java SE works. That "single" dependency just knocks it out of the park in terms of "enterprisey" REST services.
No container, no "micro profile", just JAX-RS (but you still need a JSON library). JAX-RS really elevates the game. It'll even run on the stock HTTP server.
Add "just one more" with JPA, and you get not just the whole ORM, you also get a "free" database connection pool (otherwise, an OTS connection pool would be a nice addition).
All bottled up into a simple deployable jar, no dependencies outside of a compatible JDK. No dockers, no containers, just a jar and a JDK, a JDK that can be installed anywhere (just set JAVA_HOME and put the .../bin on your path). Drag and drop. systemd fixed the need for crafty service scripts -- it can just run the jar.
JAX-RS Jersey, JPA EclipseLink, Jackson (for JSON), and the JDK is just crazy capable tool set. You can also do MVC web stuff with Jersey. Jersey comes with Validation as well. The HK2 runtime will let you do your own injection if that's your thing (not as nice as CDI, but it's "free" with Jersey).
But, alone, (plus Jackson), the JDK will let you do anything you want, just need to write some routing logic.
Java: Arrays.stream(nums).map(n -> n * n).toArray();
Kotlin: nums.map { it * it }
Python: list(map(lambda x: x*2, nums))
C#: nums.Select(n => n * n).ToArray();
Ruby: nums.map { |n| n*2 }
Rust: nums.iter().map(|&n| n * n).collect();
Perl: map { $_ * $_ } @nums;Personally, when I'm solving a problem, I like to reach for the pre-established universally understood pattern that's built into my language. Rather than using a language that doesn't have any of those things and requires me to create my own, worse, implementation that's unique to my program (or use a random 3rd-party module of dubious quality for something basic).
> requires me to create my own
Yes, how many string contains methods are there out there, as the result of everyone having to write their own.
I feel like we've jumped out of the frying pan of the 90s' OOP craze, directly into the fire of doing the same cargo cult behavior with functional programming. Always avoid loops, always use higher-order functions. It just makes sense. If you are not provided with the shotgun spread of higher-order functions out of the box, be frustrated.
I vaguely recall reactions to Haskell in the late 90s where vitriol was spewed over the lack of inheritance and classes.
Go now has slices.Contains
It has enums, and if you want exhaustive checking, use golangci-lint (as every good gopher should be already, considering the language ensured tooling would be easy to write) https://golangci-lint.run/usage/linters/#exhaustive
> You want functional constructs (map, filter), nope.
There are libraries for map/filter (just make sure you use one with deforestation)
> You want string array contains, nope.