Buffer overflows, as mentioned, are not possible in Java. There are Java (byte) arrays that more or less directly map to memory, but all array access is bounds checked (throwing an
IndexOutOfBoundsException if anybody is reading beyond the limits. This is a runtime check of course. Note too that Java has references instead of pointers (
NullPointerException is a bit of a misnomer). Pointer arithmetic is not supported. Of course
IndexOutOfBoundsException is usually not caught, so it may still be used to perform a denial of service attack.
That doesn't mean that Java isn't vulnerable to other programming mistakes. You may end up with a memory related error if you leak resources, for instance.
For good coding practices, please take a look at e.g. the Google coding practices. These mainly specify syntax related practices. For general Java programming semantics you should at least read Effective Java.
Too few people use them, but it is a good idea to perform static code analysis on your generated source code and byte code. Two well known tools are CheckStyle for source code and FindBugs for byte code. It may pay off and use special applications that can perform automated testing of code as well. There is a myriad of companies that specialize in e.g. static testing. Many of these companies perform such analysis for free for open source applications.
You need to have JUnit tests, at least for any library class you write. Performing code coverage for your Unit tests is highly recommended. I'll leave out other practices such as application level testing and code review other than to mention that they exist. To be able to do all this you should use a well defined versioning system and build environment. If you have more than one developer then continuous integration usually pays off.
One of the most known security practices is to not trust the input to your application. You may want to create a separate threat analysis for your security design.