Is it okay to use nested classes as pure data sets, kind of like other languages 'Structs'?

Viewed 41

As the title says, is it okay to use a very trivial nested class just as a data holder, to act like a Struct existent in other programming languages?

For example, imagine that I need a method to return more than one value, is it okay to use this very simple nested class for this purpose? Or is it a bad practice?

As an example, imagine a scenario where you have to draw a shape using absolute coordinates (left, top, right, bottom) and what to retrieve the x and y coordinates clicked on a screen, but instead of starting to draw the shape at those coordinates, we need to offset them to draw the shape in the center of those coords, like this example demonstrate:


public class DrawSquare {

    private class Positions {
        public int left;
        public int top;
        public int right;
        public int bottom;
    }


    //* These classes may not exist in java.
    //* They're here just to exemplify functionality.
    private Rectangle mSquare;
    private Paint mPaint;
    private Screen mScreen;

    private final int SIDE_LENGTH;

    public DrawSquare(int sideLength) {
        SIDE_LENGTH = sideLength;
        mSquare = new Rectangle();
    }

    //* Creates a square where the screen was clicked.
    public void createSquare() {
        Positions pos = processCoords(
                mScreen.getClickedX(),
                mScreen.getClickedY());

        //* Because the coords were processed, this rectangle
        //* will be created in the center of the clicked coords.
        mSquare.set(pos.left, pos.top, pos.right, pos.bottom);
        mPaint.draw(mSquare, mScreen);
    }


    //* Moves the square
    public void moveSquare() {
        Positions pos = processCoords(
                mScreen.getClickedX(),
                mScreen.getClickedY());

        //* Because the coords were processed, this rectangle
        //* will be moved to the center of the clicked coords.
        mPaint.animate(mSquare, mScreen)
                .moveTo(pos.left, pos.top, pos.right, pos.bottom)
                .setDuration(500)
                .start();
    }

    //* offset the coords to get a centered square
    private Positions processCoords(int x, int y) {
        Positions pos = new Positions();
        int halfLength = SIDE_LENGTH / 2;

        pos.left = x - halfLength;
        pos.top = y - halfLength;
        pos.right = x + halfLength;
        pos.bottom = y + halfLength;

        return pos;
    }

}

Those are just made up object types to exemplify the scenario I stated above.

Is that a good use case of a nested class?

1 Answers

That approach is almost fine, with a small nitpick:

Use a static nested class instead of an inner class:

public class DrawSquare {

    private static class Positions {
        public int left;
        public int top;
        public int right;
        public int bottom;
    }

The difference is that a static nested class does not need a reference to a DrawSquare.


In Java 14, records are a preview feature.
One of the uses for them are exactly what you are doing there:

public class DrawSquare {

    private record Positions(int left, int top, int right, int bottom) {}

Records are immutable, so you would have to change your creation a bit:

private Positions processCoords(int x, int y) {
    int halfLength = SIDE_LENGTH / 2;

    int left = x - halfLength;
    int top = y - halfLength;
    int right = x + halfLength;
    int bottom = y + halfLength;

    return new Positions(left, top, right, bottom);
}

A record will automatically create a constructor, accessors (.left()...) and overload .equals(Object other), .hashCode() and .toString() for you.

But until this feature is in standard Java (without preview), your approach is fine.

Related