Array of immutable objects initialized at compile-time I have a class that contains defines 'magic' numbers at compile time such as basic array sizes, fixed ip address, etc. so that I have one place to edit if changes are required.

In this nested class I need to define tuples of maximum and minimum values that correspond to each of 4 bands of an IR camera.  I'd like to use the data like this (for readability): 

int x = lutBounds[3].min;


Is my code below considered 'good practice'?  If not, why, and what would be better.  I'm completely self-taught in Java but try to use 'best practices' when I can recognize them.

/**
 * LUTBounds holds a band datum for the upper and lower bounds of interest.
 * @author programmer
 *
 */
 static class LUTBounds {
    final int   min;
    final int   max;

    LUTBounds(final int min, final int max) {
        this.min = min;
        this.max = max;

    }

}

// usage: int x = lutBounds[3].min;
final static LUTBounds[]    lutBounds   = { new LUTBounds(14_123, 30_123),
        new LUTBounds(14_922, 40_123), new LUTBounds(14_815, 41_123),
        new LUTBounds(14_300, 40_123) };
I would suggest an enum: they're made to encapsulate a set of distinct values known at compile time. For example, this might be the code you have as a result:

public enum CameraInformation {

    First(14_123, 30_123, "http://google.com"),
    Second(14_922, 40_123, "http://google.com"),
    Third(14_815, 41_123, "http://google.com"),
    Fourth(14_300, 40_123, "http://google.com");

    private final int min, max;
    private final String address;

    CameraInformation(int min, int max, String address) {
        this.min = min;
        this.max = max;
        this.address = address;
    }

    public int getMin() {
        return min;
    }

    public int getMax() {
        return max;
    }

    public String getAddress() {
        return address;
    }
}


The main reason for doing this is because I don't like the 0-based array index with the 1-based cameras: lutBounds[3] refers to camera 4 instead of 3, thus losing some expressiveness even for people familiar with this.

Using an enum also takes care of you having to choose a place to create those boundary values and passing them around: the enum is created once, stores its values in a central place and can be used anywhere you want. 

Usage is easy:

int min = CameraInformation.Third.getMin();