views:

141

answers:

3

I want the api of my module to only throw MyPackageSpecificException whenever anything goes wrong and the module unable to perform its task. (The original exception will be given as the cause of the MyPackageSpecificException).

Now, for one constructor I needed an URL as a parameter to locate a resource. I would also like to make an alternative constructor to which a String representation of the URL can be given:

public MyClass(String urlString) throws MalformedURLException{
    this(new URL(urlString));
}

As the URL constructor throws MalformedURLException, I want to wrap it into a MyPackageSpecificException by doing:

public MyClass(String urlString) throws MyPackageSpecificException{
    try{
        this(new URL(urlString));
    } catch (MalformedURLException e){
        throw new MyPackageSpecificException(e);
    }
}

But, the above is not valid, since the super() or this() constructor call must occur on the first line of the constructor.

The same problem applies if the super() or this() constructor throws an exception which I want to wrap into something else.

How should I solve this? Or is what I am trying to do bad practice?

+2  A: 

If it fits your code, you can use a static creator method instead:

private MyClass(String urlString) { ... }

public static MyClass createMyClass(String urlString) throws MyPackageSpecificException {
  try {
    new MyClass(urlString);
  catch (Exception e) {
    throw new MyPackageSpecificException(e);
  }
}
Zed
This is actually better than the accepted answer, because it will work for the generic case, whereas the accepted answer will only work if you can find (and "convert" to) a superclass constructor that doesn't throw undesirable exceptions. Factory pattern FTW, I guess.
Coderer
+4  A: 

Try the following:

public class MyClass
{
  private URL url;

  public MyClass(URL url)
  {
    this.url = url;
  }

  public MyClass(String urlString) throws MyPackageSpecificException
  { 
    this(toURL(urlString));
  }

  private static URL toURL(String urlString) throws MyPackageSpecificException
  {
    try
    {
      return new URL(urlString));
    } 
    catch (MalformedURLException e)
    {
        throw new MyPackageSpecificException(e);
    }
  }
}
Nick Holt
I can't believe I didn't think of this. Simple, and does exactly what I want.
Alderath
A: 

Instead of using this() have a common init() method that takes the URL argument that way it does not need to be the first line of the constructor.

public MyClass(String url) throws MyPackageSpecificException
{
  try
  {
    init(new URL(url));
  }
  catch (MalformedURLException e)
  {
    throw new MyPackageSpecificException(e);
  }
}

public MyClass(URL url)
{
  init(url);
}

private void init(URL url)
{
  // do constructor work here
}
Mark
This prevents you from assigning constructor parameters to final fields, which makes it harder to make immutable classes. Assigning final fields can only be done in the constructor.
Esko Luontola
Being a viable solution to the example i posted, this however does not work if the url must be passed to a super constructor, which is why i preferred the other solutions.
Alderath