Java is actually a much better example of where generics are used rarely and well. Containers are parameterised by exactly one thing - the type of what they contain. You don't parameterise them with different allocation strategies or comparators. Type inference means generics are often automatic, but still catch mistakes for you. And whilst nothing stops people making bad abstractions in any language, the standard library sets a pretty good example by and large.
That said, Kotlin's generics are better still and probably the best implementation I know of.