2

I know Java basics, and now I'm in the journey of reading Effective Java. The book suggest using static factory methods instead of constructors. So I have Groovy code like this:

public class Anto {
    public static void main(String[] args) {
            println Java.javaInstance()
        }
}

class Java {
    public static Java javaInstance() {
        return this
    }
}

When I compile this, I get an error like this:

Caught: org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'class Java' with class 'java.lang.Class' to class 'Java'
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'class Java' with class 'java.lang.Class' to class 'Java'
    at Java.javaInstance(Anto.groovy:9)
    at Java$javaInstance.call(Unknown Source)
    at Anto.main(Anto.groovy:3)

Where am I making a mistake?

ataylor
  • 64,891
  • 24
  • 161
  • 189
Ant's
  • 13,545
  • 27
  • 98
  • 148
  • I don't really understand why everyone is answering with singleton implementations being it one the ugliest anti-patterns out there :S. I'm upvoting sp00m's answer for now because i think the part before the "edit" is the most appropriate one. But i'd recommend reading reading [this](http://stackoverflow.com/q/4029622/581845) other SO question for other examples of static factory method effective usage and [this](http://www.informit.com/articles/article.aspx?p=1216151) article that outlines the pattern's advantages and disadvantages over using overloaded constructors. – epidemian May 04 '12 at 08:20

4 Answers4

3

You can do it using return new Java();. Static methods don't have access to this.

EDIT:

These static factories are usually singletons, which means that only one instance of the class should be used (typically, a connection to a db for example). If you want do add this dimension to your Java class, use a private static attribute as follow:

class Java {

    private static Java instance;

    public static Java javaInstance() {
        if(instance == null) {
            instance = new Java();
        }
        return instance;
    }

}
sp00m
  • 47,968
  • 31
  • 142
  • 252
  • Well, this wont create a new `Java` instance each time on the call? – Ant's May 04 '12 at 07:37
  • @Ant's Yes it will, I just edited my answer if you need this constraint. – sp00m May 04 '12 at 07:45
  • @sp00m I think the book is not talking about singletons (i'm probably wrong, i haven't read it). It probably suggests using static factory methods to instantiate objects instead of using constructors directly because when you need to have more than one way of instantiating something having overloaded constructors is not very clear/intuitive, while having different (static) methods named in an intuitive way is much preferable. I knew this idiom as "[named constructors](http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.8)" but i don't know if it has another name outside the C++ world. – epidemian May 04 '12 at 08:00
  • Interesting, I didn't know these C++ *named constructors*. You must be right, regarding to [this post](http://stackoverflow.com/questions/3852144/hiding-a-constructor-behind-a-static-creator-method). – sp00m May 04 '12 at 08:05
  • 1
    @sp00m The pattern seems to be called "static factory methods" in the Java world. [Here](http://www.informit.com/articles/article.aspx?p=1216151)'s an article describing why they are convenient over using overloaded constructors. And [here](http://stackoverflow.com/q/4029622/581845) [are](http://stackoverflow.com/q/6129026/581845) a couple of SO questions regarding their usage in the Java language. – epidemian May 04 '12 at 08:09
  • @epidemian Thanks! I didn't know this pattern. Good to know how do these `valueOf()` methods were implemented. – sp00m May 04 '12 at 08:25
2

Creating a Singleton correctly can be easy to get wrong (especially in a multi-threaded environment), so you're probably better using the Singleton annotation that comes with Groovy rather than rolling your own:

public class Anto {
  public static void main(String[] args) {
    println Java.instance
  }
}

@Singleton
class Java {
}

This transforms the Java class to:

class Java {
  private static volatile Java instance
  private Java() {}
  static Java getInstance () {
    if( instance ) {
      instance
    } else {
      synchronized( Java ) {
        if( instance ) {
          instance
        } else {
          instance = new Java()
        }
      }
    }
  }
}
tim_yates
  • 167,322
  • 27
  • 342
  • 338
  • So I have a doubt here, `Singleton` is different from `Static factory methods` concept or I'm missing somewhere? – Ant's May 04 '12 at 09:14
  • Yeah, I guess my answer was more to correct all the incorrect/bad Singleton implementations you were getting – tim_yates May 04 '12 at 09:34
  • You only actually get lazy initialization like that if you use @Singleton(lazy = true) (which you probably shouldn't since there are situations where that sort of [double-checked locking is unreliable](http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#dcl)). – Justin Piper May 04 '12 at 15:36
  • @JustinPiper Double checked locking is now only an issue on old JVMs (pre 1.5) if you write the code as above with a `volatile` – tim_yates May 04 '12 at 15:58
  • Those (plus buggy JVMs and other languages) would be the situations I mentioned. Yeah you're probably not using an old JVM (and definitely aren't if you're using Groovy) but still it seems like a bad idea to recommend using it. – Justin Piper May 04 '12 at 16:16
  • @JustinPiper Seems a bit harsh to consign it to the rubbish pile for ever because it used to be broken (and if broken JVMs were taken into account, huges swathes of Java could be scrapped thanks to GCJ). This version is miles better than sp00ms version (which will always fail for multithreaded environments, no matter which JVM), and an improvement on bmartins as it doesn't synchronize the entire method... – tim_yates May 04 '12 at 16:19
  • Mm, yes, I suppose that's true. Just being aware of the issue is probably sufficient. – Justin Piper May 04 '12 at 16:24
2

A good (albeit not specific to Groovy) example of a library that uses static factory methods that you could look at would be Google Guava. Guava uses this idiom in a number of places. For example, their Range class supports nine types of ranges, and if they used normal constructors, their signatures would conflict in several cases since the only thing you can use to distinguish them is their arguments.

Static methods on the other hand can also be distinguished by their name, so Guava defines different ones for each type of Range. Internally these methods still call a normal constructor, but it's not one that's publicly accessible.

import com.google.common.collect.Ranges
import com.google.common.collect.DiscreteDomains

final dom = DiscreteDomains.integers()

assert [1,2,3,4,5] as Set == Ranges.closed(1, 5).asSet(dom)
assert [2,3,4] as Set     == Ranges.open(1, 5).asSet(dom)

This is a useful idiom, but not one that should just be automatically preferred over a normal constructor. In situations where a normal constructor would have sufficed, you've at best written more code than you needed and at worst have made extending the class impossible, since any subclasses will still need a public or protected constructor they can call.

Justin Piper
  • 3,154
  • 1
  • 20
  • 14
0

You can't use this because static methods are not instance methods.

Each time you create a new instance of a particular class, that new object/instance as it's own state. this points to a particular instance.

Are you trying to make a singleton ? Meaning you just want a single instance of a class ?

class Singleton {
     //static reference to a particular instance
     private static Singleton instance;

     //private constructor so that it cant be called outside this class scope
     private Singleton();

     //synchronized in case your working in threaded enviroment
     public synchronized static Singleton getInstance()
     {
       if(NULL == instance)
       {
         instance = new Singleton();
       }
       return instance;
     }
}
ehanoc
  • 2,187
  • 18
  • 23