String substring can result in retaining more memory than you might expect. As such it's not a memory leak as this memory can be recovered normally.
The simplest solution is to use a recent version of Java 7, which doesn't do this. As this is the only freely supported version from Oracle, you should consider doing this anyway.
As such it was "fixed" in Java 7 update 5. IMHO it is not so much a fix as a simplification of the implementation. Taking a copy of every substring takes much more work and is likely to consume more memory, but it does mean there is one less thing to worry about.
What are all other things which can causes of memory leak in java?
Any object can be cleaned up as such it's not possible to create a memory leak in the C/C++ sense of the term. What you can do is hold onto objects incorrectly. A common example of this is forgetting to close resources like JDBC resource. This can cause you to retain memory in ways you don't expect.