Java (and probably C#) certainly supports the programming style where everything is a static method. At least, I work with people who’s first instinct is, “I can make that a static method!” But there are some subtle costs that catch up with you over time.
1) Java is an Object Oriented language. And it drives the functional guys nuts, but really it holds up pretty well. The idea behind OO is bundling functionality with state to have small units of data and functionality that preserve their semantics by hiding state and exposing only the functions that make sense in that context.
By moving to a class with only static methods, you’re breaking the “state” part of the equation. But the state still has to live somewhere. So what I’ve seen over time is that a class with all static methods begins to have more and more complicated parameter lists, because the state is moving from the class and into the function calls.
After you make a class with all static methods, run through and just survey how many of those methods have a single, common parameter. It’s a hint that that parameter should either be the containing class for those functions, or else that parameter should be an attribute of an instance.
2) The rules for OO are pretty well understood. After a while, you can look at a class design and see if it meets criteria like SOLID. And after lots of practice unit testing, you develop a good sense of what makes a class “right-sized” and “coherent”. But there aren’t good rules for a class with all static methods, and no real reason why you shouldn’t just bundle up everything in there. The class is open in your editor, so what the heck? Just add your new method there. After a while, your application turns into a number of competing “God Objects”, each trying to dominate the world. Again, refactoring them into smaller units is highly subjective and hard to tell if you’ve got it right.
3) Interfaces are one of the most powerful features of Java. Class inheritance has proven to be problematic, but programming with interfaces remains one of the most powerful tricks of the language. (ditto C#) All-static classes can’t put themselves into that model.
4) It slams the door on important OO techniques that you can’t take advantage of. So you may work for years with only a hammer in your toolbox, without realizing how much easier things would have been if you’d had a screwdriver, too.
4.5) It creates the hardest, most unbreakable compile-time dependencies possible. So, for example if you have
FileSystem.saveFile() then there is no way of changing that, short of faking out your JVM at run time. Which means that every class that references your static function class has a hard, compile-time dependency on that specific implementation, which makes extension almost impossible, and complicates testing tremendously. You can test the static class in isolation, but it becomes very difficult to test the classes that refer to that class in isolation.
5) You’ll drive your co-workers crazy. Most of the professionals I work with take their code seriously, and pay attention to at least some level of design principles. Setting aside the core intent of a language will have them pulling their hair out because they’ll be constantly refactoring the code.
When I’m in a language, I always try to use a language well. So, for example, when I’m in Java, I use good OO design, because then I’m really leveraging the language for what it does. When I’m in Python, I mix module-level functions with occasional classes — I could only write classes in Python, but then I think I wouldn’t be using the language for what it’s good at.
Another tactic is to use a language badly, and them complain about all the problems its causing. But that applies to pretty much any technology.
The key feature of Java is managing complexity in small, testable units that hang together so they’re easy to understand. Java emphasizes clear interface definitions independent of the implementation — which is a huge benefit. That’s why it (and other similar OO languages) remain so widely used. For all the verbosity and ritualism, when I’m done with a big Java app, I always feel like the ideas are more cleanly separated in code than my projects in a more dynamic language.
It’s a hard one, though. I’ve seen people get the “all static” bug, and it’s kind of hard to talk them out of it. But I’ve seen them have a big sense of relief when they get over it.