Static methods are evil
The idea behind static methods in Java is easy.
For those who don't know, a static method is a method which doesn't belong to a particular instance of the class, but it belongs to the class itself. You don't need an object implementation to use a static method. These kind of methods are often used for what are defined as "helper" methods, methods which perform small repeated tasks that are often independent from class context and hence should be performed in another class.
The advantages of static methods, however, are very little compared to the price you pay using static methods.
By using static methods, you're tightly coupling your implementation to these static methods.
Think about unit testing. Unit testing is about testing a very small unit of code, usually a class. The purpose is testing the behaviour of the class itself, and not the interactions with other units. Using mocks, you can easily simulate a desired behaviour for your dependencies in a specific test scenario. But, if you're testing some code which uses static methods, this is not easy - you may have to use specific input and then know the implementation of the static method. This not only breaks the definition of unit testing, but also requires you to change your tests if this static method implementation changes at some point.
In a world in which Inversion of Control and Dependency Injection are widely established in order to loosen coupling between modules, this is not only a bad practice, but also useless. Using a proper framework, for example Spring, you're able to inject your dependencies, and avoid to unnecessary couple implementations of unrelated logics.
There are some mocking frameworks which allow you to mock static method but, as per the boy scout rule, you should always refactor old legacy static methods into dependencies that can be injected - and then mocked when needed.
I know my APIs well, I don't need a Java book!
That's exactly what I thought, when some years ago I've been suggested a Java book. I've had enough hands-on experience (well, I thought!), I read books years ago, now why should I need a Java book?
I was completely wrong.
Mastering a programming language is not only about knowing all the keywords, constructs or a good number of classes. Mastering a language is about knowing how to effectively use it. Why I should use composition instead of inheritance? Shall I throw an exception or use a different way to handle an unexpected situation? Are interfaces a good places to store constant variables? If you're in the process of learning a language, usually you're not asking yourself such questions, as your effort it's more orientated towards learning the keywords and the data structures you use to solve your problems. You're focused on how to build the right thing.
But, as a software craftsman, it's equally important to build the thing right.
A book I've found extremely useful to polish some of my wrong coding habits is Effective Java: Second Edition by Joshua Bloch. I really felt embarrassed when, using some simple reasoning, he demolished some of my "rock solid" beliefs about how to code properly using Java. And, unsurprisingly, he's right. These simple but solid tips should be part of any Java programmer culture.
In the end, even if you know your APIs well, you may still need a Java book...
the "Boy Scout" rule
Dealing with a legacy codebase it's, at the same time, frustrating and challenging. Tightly coupled code, poor or completely absent tests, big methods and ugly variable naming... usually finding that subtle bug or try to add a new feature it's quite difficult. But, in my experience, being successful while working on such projects is even more rewarding!
I started my current job not very long ago, and one of the first stories I was pairing on involved some small changes on a JavaScript file. The file itself was massive: unused variables, long methods, even some completely unrelated functions that clearly should be elsewhere.
I was driving, and the first thing I did was getting rid of couple of unused variables, and create a file where to store the unrelated functions (we use JAWR to bundle together JavaScript files). My peer asked me why I was doing this, before even typing new lines of code for adding the feature - my answer was that "whenever we see a mess, we should leave the code cleaner for who's going to maintain it next". This is often referred as the Boy Scout Rule.
Always leave the campground cleaner than you found it.
This also applies to code. Whether you work on your own or part of a wide team, your code will be read by developers (it may be also you, after a few months you haven't touched it), which possibly will spot a better way of implementing what you've done (from renaming one variable to a more efficient way of doing some tasks). If everybody takes the time to tidy up a bit, the code will look and perform better and better as the days go by, becoming gradually easier to maintain (and consequentially, to add new features) and without allocating specifically extra time for cleaning tasks. You're showing that you care about what you do, which is one of the pillars of being a Software Craftsman.