Another problem is that Java lacks type aliases. If your data have a complicated type like List<Set<Pair<Foo, ? extends Bar>>>, you have to copy-paste this type everywhere, without a way to name it succinctly.
On top of that, Java lacks type inference, even the weakest syntactic form. This is why you often need to write a long declarations, so long that they exceed the space you may have saved by factoring out a small function. Lombok and the diamond operator somehow alleviate that, but not completely.
The lack of pattern matching, or named arguments, or null vs Optional vs Result, goes without saying.
This makes Java a very verbose language, even if the logic of your code is streamlined and economical. In many standard library APIs, it is not.
(Hence Kotlin, obviously, or Scala if you can tolerate the build times.)