Java is sometimes considered inferior to other languages for several reasons:

Ecosystem wise:
- The JVM still uses quite a bit of memory, sometimes 3-4x more memory than say Ruby or Python (which are also garbage-collected languages). There is a reason that Android phones ship with several times more system RAM than iOS devices.
- The JVM is gradually becoming only suitable for server development. Client GUI development has been mostly abandoned (with applets being deprecated, no Swing improvements for years, and JavaFX no longer being an official project), and the startup time is too slow for systems development a la shell scripts
- IDE support is actually more middle-of-the-road in my experience. IDEs can suffer from needing plugins to deal with diverse third party tools such as build systems and test systems, often themselves developed with no regards for how to integrate within a graphical environment
- Many popular libraries exist in varying states of disrepair. Lack of clear stewardship by Sun then Oracle caused several libraries to target quite ancient JVMs.
- Use of popular libraries can thus hinder your ability to use newer JVM features, and can even hinder your ability to upgrade to newer JVM releases
- exploratory and incremental development (REPL environments, exposing server app changes) have historically been pain points. I personally have seen environments where verifying a a fixed typo in a JSP template file requires a five minute redeployment.
- there are some very poor programming patterns (such as getter/setters for internal state) which have been cemented in the Java ecosystem, such that I would never recommend it for starting or junior developers.
- there is a long-standing reputation for java developers (more than developers in other languages) to treat Java as a hammer and all problems as a nail. In reality, Java is in the top ten for solving certain problems, and outside the top 50 for solving others. You simply can't be good at everything. But this means a lot of recommendations to use Java get discounted - "is this person only recommending to use Java because they have zero experience with anything else?"

The JVM and Java language themselves:
- The language has gone years with relatively few improvements.
- The language has a strong guideline of backward compatibility maintenance which hinders the efforts to improve it. As examples, lambda support was added in Java 8 without a clear model for dealing with errors, as well as Optional added without compiler support to enforce usage or VM-level support to optimize memory layout.
- There is a lot of dead weight and known bad classes in the standard library (many pre-1.2 classes like Hashtable, two date/time systems, CORBA, RMI). Some of these are finally being removed from Java by being relegated to external libraries.
- The language and JVM have an obfuscated generics system, with features (such as reified generics) likely never to be completed
- The Java language is wordy and simplistic, requiring a lot of code to accomplish tasks compared to many other languages
- Due in part to the simplicity of the Java language and focus on supporting multiple implementations of library APIs (such as multiple logging frameworks, multiple XML libraries, multiple JSON libraries, and so on) the language tends to be design-pattern-heavy and complex to navigate.
- The exception model of Java (with checked exceptions) is generally considered to have been a poor choice now.
- The class loader creates frustrating-to-diagnose issues, eating up valuable time you could be working on your application

Kotlin solves some of the language issues, but not the JVM or ecosystem issues.

Swift has a nicely developing server ecosystem, but does act differently from Java in important ways. Java has a broken intra-process isolation model, but you do still have web "containers" that allow for deployment/redeployment of applications on a running server, and which will attempt to recover gracefully from programmer errors. Many Java applications dedicate a thread for handling a request, and will handle exceptions as a failure in that request - but otherwise continue on attempting to handle future requests.

Swift is _not_ gracious about programmer errors, and will abort() on misuse such as force-unwrapping an optional without a value, or indexing an array beyond bounds. This is not unusual (node and PHP are examples of servers which will abort on certain issues) and is generally a benefit in that you get to diagnose failures by primary effects rather than secondary effects, but it does mean that you need infrastructure to catch such issues and make sure a new instance of your server is started.

(For what its worth, there have been proposals in the future (post a Swift language concurrency model) to add isolation around subprocess or actor boundaries, so that unexpected errors would only abort a "portion" of a server.)