It's not too hard to do this since Java 1.5, which added the Process and ProcessBuilder classes.
Here's an example program that starts up Firefox at a particular website:
public class OpenSite{
public static void main(String arg[]){
try { Process p = new ProcessBuilder("firefox",
"http://beginwithjava.blogspot.com/").start(); }
catch(java.io.IOException io){ }
}
}
I've compressed the various parts of the action down to one line here:
Process p = new ProcessBuilder("firefox", "http://beginwithjava.blogspot.com/").start();
I'm creating an "anonymous" ProcessBuilder object, calling its start() method, which returns a Process, which I name simply "p".
The whole thing is wrapped up in a try...catch structure because javac wants to see us deal with any I/O errors that result. In this program, I just ignore them.
So you'll want to make sure that you either catch those errors and deal with them, or that they will be unimportant enough that they don't matter.
Also note that the Java program's process will last as long as the external program you call. So if you don't shut down this instance of the firefox process, you'll have Java still running.
If you want to see something fun you can do with this on Mac, check out my article on my other blog about adding speech to the Simple Video Game Kernel.