Returning from main() will only stop the program if no other non-daemon threads are running. So, for example, if the program has a GUI, then the event thread is running, so returning from main will not stop your program.
System.exit() will, however, stop your program no matter how many threads are running.
System.exit() is a more abrupt way to stop your program. For example, if you call System.exit() from a try or catch block, any finally clause is ignored. System.exit() may be the most practical was to stop applications like Java Swing that have never-ending non-daemon threads.
The nice thing about System.exit() is that you can pass an error code that, if the JVM is set up correctly for the O/S, it should pass to whomever called your program. This is why in C main() returns int.