Static Typing is not just unnecessary, it in fact adds costs to a project.
Costs of Java-like static typing:
- Language complexity. Eg multiple inheritance (interfaces), genericity, casts, "const", exception specifications etc. Such complexity makes it harder to implement good tools, harder to learn and know the language well.
- Code verbosity. Eg declarations of functions, which mention the type of the result, the types of all arguments and the types of all exceptions thrown. Inner classes carry this load, so they are far more verbose than Smalltalk blocks and hence rarely used. Java routines tend to be 3 times the length of Smalltalk ones because of all the red tape. The more code you write, the harder it is to understand and the more opportunities for bugs and typos.
- Inflexibility. Explicit subtyping via inheritance makes it much harder for modules developed separately to work well together. They must inherit from the right interfaces/base classes. Static checking is pessimistic and claims more interface mismatches than may actually exist.
- Rigidness. A trivial change to the class hierarchy causes knock-on effects which ripple through the code. Consider throwing a new kind of exception. You have to change the signature of the routine itself, all the routines it overrides, and all the routines which call it. This encourages premature commitment to design.
- Lack of expressiveness. Static checkers are not as smart as humans, and, despite Java's language complexity, you still can't express some ideas, eg general proxies, in a natural yet statically checkable way.
The cost of Java-like static type systems is enormous.