JavaRanch Home    
 
This page:         last edited 16 February 2014         What's Changed?         Edit

Main Is A Pain   

(Level: Beginner)

When you're learning Java, chances are you'll be writing lots of exercise classes; and the first thing that most beginners do is to start cramming all their logic into main().

DON'T.

First: cramming all your logic anywhere is not a good idea, but that's beyond the scope of this little tutorial.

Write a run() method instead, and bang all your logic in there (at least to begin with ).

You'll almost certainly want to run your exercises, either from the command line or an IDE, and for that you do need a main() method; but most classes don't. If you write an application with 100 classes in it, only ONE of them needs a main() method, and it should be tiny.

.

Let's say, for the sake of argument (and this page), that you've been given an exercise to write a class that emulates a cash register, so you go ahead and start writing:

public class CashRegister {
  public static void main(String[] args) {
    // lots and lots of code
  }
}

Look familiar?

Don't do it.

Write two classes instead: One to actually do what a CashRegister does, and the other to "launch" (ie, run) it.

So, how do we do this?



Methodology:

.

First: get rid of that main() method by renaming it:

public class CashRegister {
  public final void run(String[] args) {
    // lots and lots of code
  }
}

NOTE: We've also got rid of that 'static' qualifier, so run() is now an instance method. That's very important, as you'll see below.

Note also that the method is final - you don't want anyone overriding it.

.

Next: Add a constructor that takes no arguments and, for now, leave it empty:

public class CashRegister {
  public CashRegister() {
  }

  public final void run(String[] args) {
    // lots and lots of code
  }
}

.

Next: Add a new class (in a different .java file) that runs your CashRegister class. This is the class you will actually run, and so it does need a main() method, viz:

public class CashRegisterLauncher {
  public static void main(String[] args) {
    CashRegister register = new CashRegister();
    register.run(args);
  }
}

And it should look exactly like that. ALWAYS. (obviously with appropriate class names substituted)

.

Finally: It's not absolutely necessary, but I would also suggest adding a private empty constructor to your launcher, ie:

public class CashRegisterLauncher {
  private CashRegisterLauncher() {
  }

  public static void main(String[] args) {
    CashRegister register = new CashRegister();
    register.run(args);
  }
}

What this does is prevent anyone (including you ) from accidentally creating a "launcher". It's CashRegisters we want to create, not launchers.

Furthermore, it also prevents anyone from extending CashRegisterLauncher, which you can actually make explicit by adding the 'final' qualifier to your class.

Your launcher class is now complete; and you should never need to touch it again.

.

Just a reminder: CashRegister is simply an example. Your exercise might be to write a Car, a BinaryTree, or even a Bank (always a classroom favourite).



Why this way?:

What we've just done may seem like an exercise in futility, because all we've done is to transfer all our original code from main() to run() and add a lot more.

Well, it's not.

  • The launcher is now separated from our class, so we can forget about it and concentrate on making our CashRegister class work. We can even call it something different: For example, if our "cash register exercise" is number 11 in our book or class, we could call it Exercise11Launcher - or even just Exercise11 - instead.
  • Each CashRegister is now a proper object, so if we want to we can create a whole bunch of them to make up a checkout line.
  • run()  is no longer static, which means it can access anything in our CashRegister class - static methods can only access or call other static things.
  • run() doesn't even need to be public. If your launcher class is in the same package as CashRegister (which it usually will be) you can make it package-private if you want - just remove the public qualifier. You'll soon get a feel for this stuff but, as a general rule, methods shouldn't be public unless they need to be.
You can always add public back later on if you find you need to, but you can't remove it.



SUMMARY:

So, putting all that together, and assuming CashRegister and its launcher are in the same package, we get:

CashRegisterLauncher.java:

public final class CashRegisterLauncher {
  private CashRegisterLauncher() {
  }

  public static void main(String[] args) {
    CashRegister register = new CashRegister();
    register.run(args);
  }
}

CashRegister.java:

public class CashRegister {
  public CashRegister() {
  }

  final void run(String[] args) { // Note: 'public' removed
    // lots and lots of code
  }
}

And now you can add anything else you like to CashRegister and its run() method, just like you were going to with your original main() method - except it'll be much more flexible.

.

Remember this pattern, because virtually every exercise (or application) you write - at least for a while - should follow it:

  • One - and ONLY one - launcher. And they should ALL look the same.
  • A final run() method in your "launched" class, instead of main() - and it should NOT be 'static'.
  • As many other classes as you need without main() methods.

As you get more experience you'll find you can refine it even further; but for now it should do just fine.



Alternative:

For the sake of completeness, there is another way to achieve the same result which, on the surface, may look simpler:

  • Don't write a launcher class.
  • Make run() private.
  • Add a main() method that looks exactly like the launcher one we wrote earlier.

viz:

public class CashRegister {
  public CashRegister() {
  }

  private final void run(String[] args) {
    // lots and lots of code
  }

  public static void main(String[] args) {
    CashRegister register = new CashRegister();
    register.run(args);
  }
}

Personally, I don't like it as much, because it doubles up the roles of launching and "being a cash register" in the same class; but for quick exercises - especially ones that really only need a single class - it's a reasonable alternative.

.

Hope it helps. And good luck.



CategoryWinston

JavaRanchContact us — Copyright © 1998-2014 Paul Wheaton