9

My question is simple. I'm trying to make a set of java.net.URLs that are public static final, so that any class can access them from any context, as these URLs won't change during runtime. However, when I try to create them, I get a compiler error telling me that I must catch or declare thrown a java.net.MalformedURLException, but that is impossible outside a method. Is there any way to circumvent such a constructor that throws a non-java.lang Throwable?

Some dummy code below to visualize my problem:

public class Main
{
    public static final java.net.URL STATIC_URL = new java.net.URL("http://example.com/");
    public static void main(String[] args)
    {
        GUI gui = new GUI();
        gui.setVisible(true);
    }
}
public class GUI extends java.awt.Window
{
    public GUI()
    {
        add(new java.awt.Label(Main.STATIC_URL.toString()));
    }
}

If you try to compile this, it will tell you that you can't because of line 3. Hence my question.

Ky -
  • 30,724
  • 51
  • 192
  • 308

4 Answers4

18

An "alternative" which I'd prefer to @HosamAly method:

private static final java.net.URL STATIC_URL = makeUrl("http://www.example.com");

public static java.net.URL makeUrl(String urlString) {
    try {
        return new java.net.URL(urlString);
    } catch (java.net.MalformedURLException e) {
        return null; //Or rethrow an unchecked exception
    }
}
bezmax
  • 25,562
  • 10
  • 53
  • 84
  • That is not only preferable but also circumvents the compiler error due to the final variable possibly being assigned twice. – Thomas Dec 06 '11 at 07:48
  • Max: I agree with you, that is the preferred way of doing it. @Thomas: I've fixed the error; sorry I didn't have an IDE at hand. – Hosam Aly Dec 06 '11 at 07:51
  • but is it as efficient, in terms of memory and processing time? – Ky - Dec 06 '11 at 08:20
  • @Supuhstar Static fields are filled in only once. Also I have a feeling that this method would be inlined by compiler (not sure because of that nasty "final"). Anyway, yes, it is efficient in both memory and processing time. – bezmax Dec 06 '11 at 08:58
  • 1
    @Supuhstar I'd not worry about efficiency here. Normally there are many other much more inefficient parts of ones code and often you don't actually care because what is more important in most cases is developer productivity. – Thomas Dec 06 '11 at 09:05
  • @Thomas I am insulted. I take pride in constantly going over my code to ensure it is as efficient as possible. also, this has to be efficient because there may be hundreds of this object created at once. – Ky - Dec 14 '11 at 07:35
  • @Supuhstar I didn't intend to insult you :). What I basically meant is that in favor of developer productivity you don't try to optimize every tiny bit of your code. Often there will be other performance bottlenecks which often only become obvious after thorough profiling. However, many of those are not worth the trouble because you have to invest way too much in order to squeeze out a little more performance. If productivity wouldn't matter, we'd still code our software in C or even Assembler :) – Thomas Dec 14 '11 at 09:47
  • @Thomas I understand where you're coming from, but I am still worried about poor performance. I want my programs to be as quick-starting and responsive as Chrome. – Ky - Dec 15 '11 at 03:50
  • @Supuhstar Well, the problem is, if you try optimizing **each** place in your code as much as this URL initialization stuff, you'll use up... lets say 8 extra hours. During that time you could have had coded several extra features in your app at a cost of 50msec start-up time because of skipped micro-optimizations. Is it really worth it? – bezmax Dec 15 '11 at 07:37
  • @Thomas it is very much worth it. A program is made for the end user, and it is the end user for whom I work. If there is any part of my program that the end user might not like, I must abolish it, and that includes a somewhat slow startup time. If Valve pushed out their games on time instead of held them back to polish them, they might be infamous for their bugs. Because of this, they hold their games back until they feel they have a product of which they are proud. I will **not** release a product of which I cannot be proud. – Ky - Dec 16 '11 at 02:56
  • @Supuhstar The question is: would the user recognize the extrac 50ms you squeezed out and if so would they appreciate it? – Thomas Dec 16 '11 at 13:32
  • 1
    As for the Valve example: games developers have to meet strict deadlines and they often work hard to get rid of as many bugs as possible. Often their initial pre-alpha releases have quite poor performance since they want to get something testable as quickly as possible. Then they optimize for their target platforms until they reach their performance goals (say 30fps/34 ms per frame). Once they reach that goal they won't invest much more effort in order to be a few ms faster, since they reached their goals. They don't optimize areas where optimizations most likely have no benefit. – Thomas Dec 16 '11 at 13:34
  • I believe they will, especially since individual class loading times add up fast. As for your counter to the Valve example, they indeed do optimize the performance. Try playing Portal 2 on an older computer, which just meets the system requirements, and then try playing Portal. Portal 2 will almost always run better because Valve invested more time and effort into improving the source engine. Their games are "late" because they care about the end product. My programs have no release time, and I believe no one's should. Any well-made program should be released only after the creator is proud. – Ky - Dec 17 '11 at 04:17
  • @Supuhstar So what you are saying is that Portal 1 was **not** optimized to the edge and that it had to be released with performance issues, right? And you are using that to prove that Valve only release perfect products? Am I missing something in your statements? – bezmax Dec 17 '11 at 16:34
  • You're missing the pride. My philosophy is one of pride. If I can't be proud of a product, I can't release it. Now, please tell me this is the key to that oh-so-private information you've been withholding. Which method of static initialization is faster? – Ky - Dec 18 '11 at 05:08
  • 2
    Technically, the "fastest" way for static initialization would be what @HosamAly proposed. However, to make it faster than my solution - you would need to bundle as many as possible URL initializations inside of one try-catch block. The reason for that is that try-catch operation is somewhat resource-heavy. So if you use try-catch for **each** variable, it will be somewhat slower than if you bundle them all into one try-catch block. However, personally I prefer a clear and understandable code. You will see what I mean after you actually try initializing several URLs in one try-catch block. – bezmax Dec 18 '11 at 13:02
  • 1
    In the 5 years since posting this question and accepting an answer, I've decided to make this the accepted answer since it's a lot easier to understand, and much more functional. – Ky - Jan 08 '17 at 19:27
  • 1
    @Supuhstar What about the pride? ;) – bezmax Jan 10 '17 at 17:22
  • @bezmax haha it's still there! Just also now balancing pride of speed with pride of exemplary code. Working with teams changed me :P – Ky - Jan 10 '17 at 17:44
14

Use a static initializer:

public class Main {
    private static final java.net.URL STATIC_URL;
    static {
        java.net.URL temp;
        try {
            temp = new java.net.URL("http://www.example.com");
        } catch (java.net.MalformedURLException e) {
            temp = null;
        }
        STATIC_URL = temp;
    }
}

Note: The usage of a temporary variable is required to avoid a compilation error about assigning to the final static field twice. If the field is not final, the assignment could be done directly.

Community
  • 1
  • 1
Hosam Aly
  • 41,555
  • 36
  • 141
  • 182
7

If you're sure you want to hardwire a URL. Are you sure? java.net.URL is one of the most comprehensively broken classes in the JDK. In regards to use as a "constant", there is DNS lookup involved and it uses a mutable static (albeit one guarded by a security check, if you have a SecurityManager installed).

If it's just one, a static initialiser should be fine.

private static final java.net.URL STATIC_URL;

static {
    try {
        STATIC_URL = new java.net.URL("http://example.com/");
    } catch (java.net.MalformedException exc) {
        throw new Error(exc);
    }
}

(Note, you can't qualify the static field name with the class name.)

Note: You really do not want a null - throw an error of some sort and stop the class loading. I've made the constant private as it really isn't the sort of thing you want dependencies on.

If you have lots, then a method for the common code and assignment at the site of the definition is appropriate.

private static final java.net.URL STATIC_URL = constantURL("http://example.com/");

private static URL constantURL(String str) {
    try {
        return new java.net.URL("http://example.com/");
    } catch (java.net.MalformedException exc) {
        throw new Error(exc);
    }
}

Again, no nulls!

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
0

The only way I got this to compile is by removing final and using the static initializer block.

/**
 * 
 */
package com.neurologic.example;

import java.net.MalformedURLException;
import java.net.URL;

/**
 * @author The Elite Gentleman
 * @since 06 December 2011
 *
 */
public class StaticUrlTest {

    public static URL url = null;

    static {
        try {
            url = new URL("http://www.google.com");
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

    }

}
Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
  • The `final` keyword could still be used. Please see my updated answer. – Hosam Aly Dec 06 '11 at 07:48
  • @Hosam Aly, no it won't. This solution (posted above) is the **only** solution that compiles. Yours doesn't. I've compiled it using IDE, as well as on command line, and yours failed. – Buhake Sindi Dec 06 '11 at 07:59
  • @Supuhstar, I'm not "high-and-mighty". I just posted a code that I tested instead of rushing to post answers just for point. Besides, SO was designed to give solutions/answers that **works**, and not for greed. :-) – Buhake Sindi Dec 06 '11 at 08:24
  • sorry, I just assumed that you were being pretentious when you said something to the effect of "my solution is the **only** one that works, so yours can't be right" – Ky - Dec 06 '11 at 08:26
  • @TheEliteGentleman Mine compiles with javac 1.6.0_26. Which compiler version are you using? – Hosam Aly Dec 06 '11 at 08:29
  • @Hosam Aly, I have the same, 64 bit version. You've edited your code, and it's effectively, exactly as mine (except, I don't use `temp` variable). :-) – Buhake Sindi Dec 06 '11 at 08:31