Интерфейс с константами
В интерфейсах удобно писать константы, т. к. все объявления в них public static final. Такие константы вследствие используются посредством статических импортов: import com.example.Constants.*.
Проблема: интерфейс не объявляет методы, но нет языковых механизмов, которые помешают его реализовать. Если это сделать, то константы, деталь реализации класса, будут видимы извне.
См. также: Joshua Bloch, Effective Java, Use interfaces only to define types. 2nd edition: Item 19, p. 98; 3rd edition: Item 22, p. 107.
Класс с константами
Финальный класс с приватным конструктором решает некоторые проблемы предыдущего варианта: его нельзя ни унаследовать, ни инстанцировать (создать экземпляр).
Свалка констант
Оба вышеупомянутых примера можно назвать свалкой констант. У константы, как и у любого другого объявления, должна быть минимальная область видимости, чтобы код был слабосвязанным. Класс, в который сваливают все константы, нарушает этот принцип: константы из зон ответственности разных классов оказываются в одном месте.
Любая константа должна находиться в том классе, в котором используется и в контексте которого имеет смысл.
Примеры
int Integer.MAX_VALUE
Pattern SomeNetworkRelatedClass.URL_PATTERN
String Entity.SOME_FIELD
Антипримеры
int Constants.MAX_INTEGER
Pattern Constants.URL_PATTERN
String Constants.SOME_FIELD
В антипримерах потерян контекст, а константы уже не могут быть приватными.