DEV Community

Mark Rubin
Mark Rubin

Posted on

Where should main live

This is part of a brief series on Good Habits For Java Programmers.

A Java program needs to have a method with the signature
public static void main(String args[]) in some class. It serves as the entry point for your program. When you run your program, the Java runtime finds this magic entry point, calls it, and you're off to the races. You'll have to house this method in a class, because that's just how it works. The question entertained by this post is in which class should the main method go.

In How To Get Out Of Main And Reduce Static, we moved most of our logic out of our public void static main method into our Square class and ended up with this code:

public class Square {
    private float sideLength = 0.0f;

    public static void main(String args[]) {
        Square square = new Square();
        square.setSideLength(3.2f);
        System.out.println("The area of the square is " + square.getArea());
        System.out.println("The perimiter of the square is " + square.getPerimeter());
    }

    public void setSideLength(float length) {
        sideLength = length;
    }

    public float getArea() {
        return sideLength * sideLength;
    }

    public float getPerimeter() {
        return 4 * sideLength;
    }
}
Enter fullscreen mode Exit fullscreen mode

It's a good idea to review that post. In it, I noted that we should think of main as just a contractual rendezvous point with the Java runtime. It's how the Java runtime finds a place to start your program, and that is its primary role. Given that, does main belong in Square? It really doesn't have anything to do with a square, the shape. If I ask you to tell me the properties of a square that you should model with a Square class, you'll tell me about side length and the formulas for the area and perimeter of a square and the like (maybe what the angle measurements are for a square, etc.), but you wouldn't say that they have a contractual entry point through which a Java runtime can start a Java program.

So with that in mind, it should seem off that main is a method of Square. It can be convenient to put it there: in this, case it keeps your program all in one file. But conceptually, it's odd.

I'll pile on here. What if you enhance your program to hardcode values for other shapes (e.g. circle, triangle) and output their areas and perimeters? Would you insist on keeping your main in Square? Why Square and not Circle?

Here's a similar point. Let's say you were a reader of the enhanced program and not its author: would you know which file/class had the magic main method in it from class names such as Square, Circle, Triangle? Would you say to yourself "Oh, it has to be in Square. Why would it be anywhere else?". Once programs start to get a bit large -- even just a few files -- I find myself having to hunt for students' main implementations.

So I recommend having a Main class (or some class with "Main" in the name) whose sole purpose is to house the public static main method. Make a Main class and put your public static void main in there. Now it'll be obvious to you and to everyone where your main method lives. And however your program grows over time, you won't have to move it from one class to another to accommodate the growth. I need to note that this is not universal convention, although I bet not many would dislike it much: it can never really hurt, and it can help.

That also aligns nicely with the idea that main is just a contractual entry point. Classes should model something, and if you follow this advice, your Main class is then modeling that it's the entry point for your program. It advertises no more than that, but it does advertise that its purpose is to house main (unlike Square's name). So in our example, we'd have:

// In Main.java
public class Main {
    public static void main(String args[]) {
        Square square = new Square();
        square.setSideLength(3.2f);
        System.out.println("The area of the square is " + square.getArea());
        System.out.println("The perimiter of the square is " + square.getPerimeter());
    }
}

Enter fullscreen mode Exit fullscreen mode
// In Square.java
public class Square {
    private float sideLength = 0.0f;

    public void setSideLength(float length) {
        sideLength = length;
    }

    public float getArea() {
        return sideLength * sideLength;
    }

    public float getPerimeter() {
        return 4 * sideLength;
    }
}

Enter fullscreen mode Exit fullscreen mode

Does main still contain too much?

I'm going to get more controversial here. I think even this version has main doing too much. I'd prefer that Main call a method on another class that's well named for doing the work here for creating our Square. I'd like main to have as little logic as possible: it's there to fulfill our contract with Java and nothing else. Anything else that we do that's interesting should be done in a class whose purpose is to do that thing. I'm advocating keeping this contract with Java separate from everything else. I'm pretty extreme here. I'd rather see something like

// In Main.java
public class Main {
    public static void main(String args[]) {
        Driver.startTheProgram();
    }
}
Enter fullscreen mode Exit fullscreen mode
// In Driver.java
public class Driver {
    public static void startTheProgram() {
        Square square = new Square();
        square.setSideLength(3.2f);
        System.out.println("The area of the square is " + square.getArea());
        System.out.println("The perimiter of the square is " + square.getPerimeter());
    }
}
Enter fullscreen mode Exit fullscreen mode
// In Square.java
public class Square {
    private float sideLength = 0.0f;

    public void setSideLength(float length) {
        sideLength = length;
    }

    public float getArea() {
        return sideLength * sideLength;
    }

    public float getPerimeter() {
        return 4 * sideLength;
    }
}
Enter fullscreen mode Exit fullscreen mode

Now Main does nothing than fulfill our contract with the Java runtime, Driver is in charge of our logic for how to drive our program, and Square simply models a Square. If we want our program to do more, we put more in Driver. If we change our mind about what to do first, we either change Driver's startTheProgram implementation or we create another class that we call from main to do something first, and have it call Driver, etc.

I have to admit this: you'll find lots of folks using Main classes or appreciating my point about having a separate Main class; you'll probably find fewer excited about my creating yet another class, such as Driver that main calls, especially for small programs.

Top comments (0)