I've been a zone leader with DZone since 2008, and I'm crazy about community. Every day I get to work with the best that JavaScript, HTML5, Android and iOS has to offer, creating apps that truly make at difference, as principal front-end architect at Avego. James is a DZone Zone Leader and has posted 639 posts at DZone. You can read more from them at their website. View Full User Profile

Declaring Final Variables Elegantly Using The Assigner Design Pattern

03.04.2010
| 8141 views |
  • submit to reddit

A final variable is used to define a constant value and reference, and can only be defined once. In most cases, declaring a final variable is just a matter of assigning to a primitive value or an object reference directly.  However, in some cases, declaring a final class/instance variable may be more involving especially it gets assigned from a method that throws an Exception (eg API for database access, web access), or it may involve multiple statements.

 Editors Note: This content was submitted by geekycoder

In such cases, the code may become cluttered with class helper methods and dummy temporary variables that help define the final variable, making the code look less elegant and harder to maintain. The following common ways of declaring a final variable in those situations might look familiar to many.

Declaring final variable by instance/class method

image

 

 Declaring final variable by instance/class variable with static/instance initializer.

image

The aforementioned ways definitely get the work done but at the cost of elegancy. The helper method and variable help to define the final variable but it inevitably becomes part of class method and variable.

 

Recommended way: Assigner Design Pattern

A better way to declare final instance/class variable is to use Generic method and interface with the advantages of

  • forcing initializing method in the same statement  as the final variable declaration.
  • reusing as design pattern (term: Assigner Design Pattern) and enhancing code readability

There is generic helper class whose interface and method accept a parametric type similar to the type of final variable.  The advantage of using Generics is that the type mismatch will be caught at compile time rather than runtime. This design pattern is termed Assigner because it assigns value to a variable from initializing method.

 

image

 

Using the design pattern, the code becomes cleaner and elegant.

image

The above can be downloaded -  assigner.zip (1kb)

Some will probably argue that Assigner Design Pattern may not be efficient compare to the first two ways since additional bytecode classes are generated for Assigner helper class and inner class. However, like other design patterns, code readability and reusability may outweigh the negligible performance loss and inefficiency.

Tags:

Comments

Ricky Clarkson replied on Thu, 2010/03/04 - 6:04am


final String you = new Object() {
    String must() {
        try {
            return "be";
        } catch (RuntimeException e) {
            return "kidding if you think the code you showed in the article is any good." + 
                "  Or, perhaps, an enterprise programmer paid by the line.";
        }
    }
}.must();
No need for any 'assigner', just a bit of knowledge of Java. Alternatively, stop using exceptions.

Fab Mars replied on Thu, 2010/03/04 - 7:56am

I don't buy this one. That was a joke right? Elegant...Readability...Reusability...come on!

That's how we end up struggling with our junior developers: just because they're spending all their time implementing every crazy pattern they've seen on the internet instead of focussing on the real useful business code our customers are asking for.

I also second the previous comment regarding exceptions: since the code you're using to assign your final variable can't throw exceptions, you're bound to pretend they will never happen and mask yours somehow (rethrow a RuntimeException which would probably end up killing your program, or use an infamous printstacktrace/log), after which your class won't be correctly initialized anyway... We're all confronted with that.

Alessandro Santini replied on Thu, 2010/03/04 - 9:38am

Glad to see comments from people who have awakened from the Matrix...

GeekyCoder coder replied on Thu, 2010/03/04 - 11:14am

Hi, guys.

 Of course, there is many ways to accomplish the same thing. Some prefer standardised solution, some prefer their own way. After all, a design pattern is just a pattern. Use whatever you feel comfortable with, and use whatever works for you. 

<:^}

GeekyCoder coder replied on Thu, 2010/03/04 - 11:18am

 Hi,

What I define is a just standard pattern and whatever you want to put into the body, whether exception handling (good or bad) or laundry cloth will be up to you.

cheers

Rogerio Liesenfeld replied on Thu, 2010/03/04 - 12:18pm

I got the impression the post author simply doesn't know a basic fact about the Java language: final instance fields can be assigned in constructors; they don't have to be assigned in the declaration.

GeekyCoder coder replied on Thu, 2010/03/04 - 2:00pm in response to: Rogerio Liesenfeld

The pattern can be used in many ways and not just confined to my code example. My code example is just to illustrate one example use of the pattern, which happen to use a class to demonstrate the pattern. I think we should look wider beyond what you just see from the code example. 

Hint: How about declaring variable in interface (constructor is out) ? Can this pattern be applied too ?     <:^}


public interface IConstant
{
     String IDENTIFIER = Assigner.assign(
        new Assigner.IAssignable<java.lang.String>()
        {
            public String initialize()
            {
                // eg database and web access through API
                // that throws exception.
                try
                {
                    java.net.URL _url = new java.net.URL(
                        "http://www.java.com");
                    return _url.getHost();
                }
                catch (java.net.MalformedURLException _ex)
                {
                    _ex.printStackTrace();
                }
                return "error";
            }
        });
}

As I have mentioned, whether it is a good practice to handle exception this way will be up to  individual to decide as it is a matter of preference.  

cheers ...

GeekyCoder coder replied on Thu, 2010/03/04 - 2:02pm

Anyway, for those who are interested to read more about final variable

 check this out.

http://renaud.waldura.com/doc/java/final-keyword.shtml#many

Rogerio Liesenfeld replied on Thu, 2010/03/04 - 3:40pm in response to: GeekyCoder coder

Yes, but note that *instance* fields cannot be defined in Java interfaces. I think that assigning the final instance field in a constructor is the right way to go, if for any reason it cannot be assigned in the field declaration. In a constructor you can freely use "try" blocks.

Ricky Clarkson replied on Fri, 2010/03/05 - 2:30am


class YouCannot {
  final Define it;
  YouCannot() {
    try {
      it = new Define("this way");
    } catch (RuntimeException e) {
      it = because.definiteAssignment(isScrewed);
    }
  }
}

Mladen Girazovski replied on Fri, 2010/03/05 - 5:14am

As I have mentioned, whether it is a good practice to handle exception this way will be up to  individual to decide as it is a matter of preference.  

I'm not sure if your post was meant to be taken seriously or if you're taking us for a ride..i'll take the bait.

You don't reale handle the Exception, instead, you're initilaising the variable with "error"... now, how can you call that "Exception Handling"??? You're ignoring it, nothing else.

And no, it is not a matter of personal preference, there is something called best practices for exception handling, which is quite the opposite of what you've showed.

 

Andreou Dimitris replied on Fri, 2010/03/05 - 7:57am

Oh, the atrocities I've seen in the name of "elegance".

Rogerio Liesenfeld replied on Fri, 2010/03/05 - 11:53am in response to: Ricky Clarkson

class ButYouCan {
  final Define it;
  ButYouCan() {
    Define theValue;
    try {
      theValue = new Define("this way");
    } catch (RuntimeException e) {
      theValue = because.definiteAssignment(isForLocalVariablesNotFields);
    }
    it = theValue;
  }
}

Jochen Bedersdorfer replied on Fri, 2010/03/05 - 12:37pm

I am developing in Java for 14 years now, but I never ever had the urge to develop an interface or abstract class for initialization purposes only.

I fail to see reuse or elegance here, I'm afraid.

 It is exactly this unnecessary complexity that lets people perceive Java as clumbsy or heavyweight.

Please reconsider using or promoting this pattern.

Thanks!

 

Till Omann replied on Fri, 2010/03/05 - 2:45pm

Declaring anonymous inner classes is IMO always a critical point. I agree with most software architects to use it the less as possible. I agree that the (default) constructor is the right place for most cases to assign final variables.

The exception handling? As commented above ... ^^

Hopefully closures will soon find their way into Java. Closures are a nice and more readable replacement for the usage of anonymous inner classes and they keep your packages clean from "one method interfaces".

Stephane Vaucher replied on Fri, 2010/03/05 - 6:02pm

I fail to see why this is a design pattern. What is the commonly occurring pattern you are trying to solve? Most other people responding fail to see why you are doing something complicated like this. For me (at least) a final "variable" should represent a value that should not change, and which should be closely linked to the instance itself. If the creation process fails (thus there is an exception), why should the object be created? If there is a reason that might justify its creation nonetheless, then what Rogerio mentions seems more intuitive. A problematic situation I have been confronted with is when you are chaining constructors. The compiler does not allow an object to invoke an instance method before/during this(). I either use a factory method (which should be mentioned is a valid alternative to this "pattern"). An example that fails is the following:
    public DeclareFinalVariableByAssigner() {
        this(name()); // NO GOOD... 
    }

    private DeclareFinalVariableByAssigner(String name) {
        IDENTIFIER = name;
    }

    private String name() {
        String tmp;
        try {
            java.net.URL _url = new java.net.URL("http://www.java.com");
            tmp = _url.getHost();
        } catch (java.net.MalformedURLException _ex) {
            _ex.printStackTrace();
            tmp= "fpp";
        }
        return tmp;
    }

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.