4

Is the any difference in performance and/or any other benefits we can get when using final keyword with constant utility class. [ This class contains only static final fields and private constructor to avoid object creation]

public class ActionConstants {
    private ActionConstants()  // Prevents instantiation
    {   }

    public static final String VALIDFIRSTLASTNAME = "[A-Za-z0-9.\\s]+";    
    public static final String VALIDPHONENUMBER = "\\d{10}";
    ...
    ...
}

Only diffrence is class is made final

 public final class ActionConstants {
    private ActionConstants()  // Prevents instantiation
    {   }

    public static final String VALIDFIRSTLASTNAME = "[A-Za-z0-9.\\s]+";    
    public static final String VALIDPHONENUMBER = "\\d{10}";
    ...
    ...
}

I like to know, is there any benefits there in using final and what is the correct way to define class for constants.

Gnanz
  • 1,833
  • 5
  • 24
  • 51

5 Answers5

5

There is no benefit. It does not change anything regarding your static final attributes.

When a class is made final, the compiler can take advantage of this for overridable methods (static methods cannot be overriden, at best, they hide those one in inherited classes).

Since the class is final, the compiler knows none of its method can be overriden. So, it can compute cases where polymorphism code does not need to be generated (i.e., the code finding the right 'version' of the overriding method according to the object instance at runtime). Hence, an optimization is possible.

If you want to make a class truly unique, you can use something like this:

public enum ActionConstants {

    INSTANCE;

    public static final int cte1 = 33;
    public static final int cte2 = 34;

}

And if you are not interested in a class instance at all, just put all your constants in an interface.

Jérôme Verstrynge
  • 57,710
  • 92
  • 283
  • 453
  • Not sure you need an `INSTANCE`. I would have an enum with no instances. – Peter Lawrey May 26 '11 at 06:22
  • 2
    Normally "Interfaces should be used only to define types. They should not be used to export constants." – Gnanz May 26 '11 at 06:22
  • @Peter Lawrey You need to provide at least one value for the enum, I called mine INSTANCE, but it could be anyhting... – Jérôme Verstrynge May 26 '11 at 15:07
  • 1
    @JVerstry, Where does it say you need a minimum of one? Have you tried removing the INSTANCE and putting just `;` – Peter Lawrey May 26 '11 at 15:34
  • @JVersty, Some would consider an enum with no instances a hack. ;) – Peter Lawrey May 26 '11 at 17:10
  • In most cases the AOT compiler cannot make any use of the information that a class is `final`. The JIT compiler can, of course, but it can figure out the information by itself anyway. http://www.ibm.com/developerworks/java/library/j-jtp1029/index.html – Binil Thomas May 26 '11 at 17:13
  • @Binil Thomas This is false, AOT compilers can ALWAYS make use of information that a class is final to perform optimization by generating less bytecode. What your link refers to is inlining, which a different type of optimization than what I am referring to. The author visibly fails to understand the real motivation behind using final and pushes his own assumptions on people's motivations. – Jérôme Verstrynge May 26 '11 at 22:25
  • @JVerstry if an AOT compiler uses final keywords on classes to identify monomorphic calls, that assumption can fail at runtime. Brian Goetz's explanation I linked to makes sense to me, so please explain what other optimizations an AOT incremental compiler can do with final keyword when applied to classes. – Binil Thomas Jul 20 '11 at 09:19
  • It has to do with polymorphism. You need code to figure out which overridden method to call at runtime. Final means less polymorphism, means less code => useful information for optimization. Not need to figure out which method to call at runtime. It can be done at compile time. – Jérôme Verstrynge Jul 20 '11 at 09:28
  • @JVerstry Suppose you have three files - `A.java`, `B.java` and `Main.java`. `A.java` contains the lines `class A { final int foo() { return 1; } }`, `B.java` contains the lines `class B { void bar(A a) { System.out.println(a.foo()); } }` and `Main.java` contains the lines `class Main { static void main(String[] args) { A a = new A(); B b = new B(); b.bar(a); }`. When `A.java`, `B.java` and `Main.java` are compiled, and `Main.class` executed, one expects to see `1` printed on the console. (continued..) – Binil Thomas Sep 17 '11 at 20:32
  • @JVerstry Your argument seems to be that since `A.foo()` is marked `final`, while compiling `B.java` file the compiler can be sure which implementation of `foo` needs to be called - i.e. the one in `A`. (continued..) – Binil Thomas Sep 17 '11 at 20:33
  • @JVerstry After `A.java`, `B.java` and `Main.java` are compiled, I edit `A.java` as `class A { int foo() { return 1; } }` and add a new file `ASub.java` as `class ASub extends A { int foo() { return 2; } }` and edit `Main.java` as `class Main { static void main(String[] args) { A a = new ASub(); B b = new B(); b.bar(a); }` and compile `A.java`, `ASub.java` and `Main.java`. Now when I run `Main.class`, I am supposed to see `2` printed on the console. But if `B.java` had been compiled to call `A.foo()` method, you will see `1`, which is the wrong answer. (continued ..) – Binil Thomas Sep 17 '11 at 20:33
  • @JVerstry Hence, my assertion that while compiling `B.java`, even if the compiler notices that `A.foo()` is `final`, it cannot assume that method call resolved to the `A.foo()` implementation. – Binil Thomas Sep 17 '11 at 20:34
  • @Binil You did not understand my argument. The code that has to check for polymorphism (under the hood) is never going to be located in B's compilation, but in A's compilation only. B will call a well defined point in A, and this is where the correct version of the method will be determined if A is not final. – Jérôme Verstrynge Sep 17 '11 at 21:01
  • @JVerstry I C. I will check and get back to you. – Binil Thomas Sep 17 '11 at 21:08
  • @JVerstry Can you show me an example where `A` gets some special code for polymorphic dispatch because one of its methods is marked `final`? I tried it on Sun 1.6 compiler and the results of decompilation are at: http://pastie.org/2549933 . I did not find any special treatment given to the `final` method. – Binil Thomas Sep 17 '11 at 22:36
  • @Binil This only means that this compiler does not take advantage of this information. If the byte code where interpreted, there would we some code somewhere in the interpreter dealing with polymorphism inefficiently. Yet the 'final' information could still be used more efficiently at compile time to signal that executing this polymorphism code is unnecessary. The information could be used, but is not necessarily used. Too bad. – Jérôme Verstrynge Sep 18 '11 at 11:46
  • @JVerstry I agree that a pure interpreter might suffer from the extra overhead of the dynamic polymorphic dispatch. But I am fairly certain that no production compiler (which emits JMV bytecodes) implement the scheme you outlined - if it did, the resulting bytecodes will have different semantics when run on a standard JVM. So yes, in a hypothetical language, marking a class `final` helps performance. But in Java, as is popularly implemented, it makes little difference. I once removed `final` modifiers from all classes in a low-latency trading system codebase and observed no performance impact. – Binil Thomas Sep 18 '11 at 17:27
  • @Binil 'if it did, the resulting bytecodes will have different semantics when run on a standard JVM' -> Not at all, if you call a method directly rather than computing which method version should be called when the answer is always the same does not modify semantics. Why do you think Proguard attempts to make all classes final? – Jérôme Verstrynge Sep 18 '11 at 17:50
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/3575/discussion-between-jverstry-and-binil-thomas) – Jérôme Verstrynge Sep 18 '11 at 17:50
3

If you are looking for improved performance you are better off pre-compiling your patterns like

public static final Pattern VALIDFIRSTLASTNAME = Pattern.compile("[A-Za-z0-9.\\s]+");    
public static final Pattern VALIDPHONENUMBER = Pattern.compile("\\d{10}");

Using a final or not is, very small compared to the cost of using a regular expression.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
1

There is no real benefit, but it does enforce your expectation that nothing extends your class. That might make it easier in the long term to, for example, search your code for all uses of the constants since they will be guaranteed to be XXX.abc and not YYY.abc where YYY extends XXX.

Lawrence Dol
  • 63,018
  • 25
  • 139
  • 189
1

You should avoid using "classes for constants". It means a bad ddesign. Place constants in classes that operate with them. Avoid using public constants as well. It should be exception, not a normal practice.

artplastika
  • 1,972
  • 2
  • 19
  • 38
0

To use a class for constants is uncommon. In most cases an interface is used. This would be accessible by ActionConstants.VALIDFIRSTLASTNAME:

public interface ActionConstants {
  static final String VALIDFIRSTLASTNAME = "[A-Za-z0-9.\\s]+";    
  static final String VALIDPHONENUMBER = "\\d{10}";
  ...
}

Since Java 5 you can also use an enum. An enum can have members or extended functionality.

The second example uses a simple member (here with a generic approach if you have different constant types, else you can also use a String member):

public enum ActionConstants {

  FIRSTLASTNAME("[A-Za-z0-9.\\s]+"),
  PHONENUMBER("\\d{10}");

  private final Object value;

  private ActionConstants(Object value) {
    this.value= value;
  }

  @SuppressWarnings("unchecked")
  public <T> T getValue() {
    return (T)value;
  }

}

String value = ActionConstants.FIRSTLASTNAME.getValue();

The last example uses extended functionality when all constants are of the same type. You can use it like ActionConstants.PHONENUMBER.isValid("0800123456"):

public enum ActionConstants {

  FIRSTLASTNAME("[A-Za-z0-9.\\s]+"),
  PHONENUMBER("\\d{10}");

  private final Pattern pattern;

  private ActionConstants(String pattern) {
    this.pattern = Pattern.compile(pattern);
  }

  public void isValid(String value) {
    return pattern.matcher(value).matches();
  }

}

Both versions allow the use of static imports.

Arne Burmeister
  • 20,046
  • 8
  • 53
  • 94