如何创建一个静态不可变的Java.net.URL?

9
我的问题很简单。我想创建一组公共静态的java.net.URL,以便任何类都可以从任何上下文中访问它们,因为这些URL在运行时不会更改。然而,当我尝试创建它们时,编译器会报错,告诉我必须捕获或声明抛出一个java.net.MalformedURLException,但是在方法外部这是不可能的。有没有办法规避这样一个构造函数,它会抛出非java.lang的Throwable? 下面是一些虚拟代码,以可视化我的问题:
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()));
    }
}

如果你尝试编译这个代码,会提示你由于第三行无法编译。因此我有一个问题。
4个回答

18

以下是我相对于@HosamAly的方法更"优"的替代方案:

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
    }
}

1
@Supuhstar 我不会担心效率问题。通常情况下,代码中还有许多其他更加低效的部分,并且你并不在意,因为在大多数情况下,更重要的是开发人员的生产力。 - Thomas
1
关于 Valve 的例子:游戏开发者必须遵守严格的截止日期,他们通常会努力消除尽可能多的错误。通常情况下,他们最初的预阿尔法版本性能相当差,因为他们希望尽快获得可测试的东西。然后,他们针对目标平台进行优化,直到达到其性能目标(例如每帧30fps / 34毫秒)。一旦达到该目标,他们就不会再投入太多精力以使速度再快几毫秒,因为他们已经达到了目标。他们不会优化那些最有可能没有任何好处的区域。 - Thomas
2
从技术上讲,静态初始化的“最快”方法是@HosamAly提出的方法。然而,要比我的解决方案更快,您需要将尽可能多的URL初始化捆绑在一个try-catch块中。原因是try-catch操作有点资源密集型。因此,如果您为每个变量使用try-catch,它将比将它们全部捆绑到一个try-catch块中要慢一些。然而,就个人而言,我更喜欢清晰易懂的代码。当您实际尝试在一个try-catch块中初始化多个URL时,您将会明白我的意思。 - bezmax
1
在发布这个问题并接受答案的5年里,我决定将这个答案作为被接受的答案,因为它更容易理解,而且功能更强大。 - Ky -
1
@Supuhstar 那骄傲呢?;) - bezmax
显示剩余14条评论

14

使用 静态初始化器

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;
    }
}

注意: 为了避免在 final static 字段分配两次时出现编译错误,需要使用临时变量。如果字段不是 final,那么可以直接进行赋值。


编译器会抱怨STATIC_URL没有被初始化(因为你使用了final)。 - Buhake Sindi
编译器错误:变量STATIC_URL可能未被初始化。 - Buhake Sindi
2
我想建议也使用java.net.URI。如果使用需要URL的库,请在那一点上使用toURL()方法。 - Flame

7
如果您确定要硬编码URL,请注意,java.net.URL是JDK中最全面损坏的类之一。在使用“常量”方面,涉及DNS查找并使用一个可变的静态变量(虽然受到安全检查的保护,如果您安装了SecurityManager)。
如果只有一个URL,静态初始化程序应该就可以了。
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);
    }
}

(注意,您不能使用类名限定静态字段名称。)
注意:您真的不想要一个“null” - 抛出某种错误并停止类加载。我将常量设为“private”,因为它确实不是您想要依赖的类型。
如果您有很多,则适合在定义位置使用通用代码和分配的方法。
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);
    }
}

再次强调,不要有空值!


3
+1表示赞同不允许有空值。如果您的常量之一已经被炸了,继续进行是没有意义的。我同意。 - Cameron Skinner

0
我唯一编译成功的方法是去掉final并使用静态初始化块。
/**
 * 
 */
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

    }

}

final关键字仍然可以使用。请参考我的更新答案。 - Hosam Aly
@Hosam Aly,不会。这个解决方案(如上所述)是唯一可以编译的解决方案。你的解决方案无法编译。我已经在IDE上编译过它,也在命令行上编译过,而你的解决方案失败了。 - Buhake Sindi
@Supuhstar,我并非高高在上。我只是发了一段我测试过的代码,而不是为了分数而匆忙回答。此外,SO 的设计是为了提供可行的解决方案/答案,而不是贪婪。 :-) - Buhake Sindi
抱歉,我误以为你在说“我的解决方案是唯一可行的,所以你的肯定是错的”时有点自命不凡。 - Ky -
@TheEliteGentleman 我的代码使用 javac 1.6.0_26 编译通过。你使用的编译器版本是什么? - Hosam Aly
@Hosam Aly,我也是64位版本。你已经编辑了你的代码,它和我的代码实际上完全一样(除了我不使用“temp”变量)。 :-) - Buhake Sindi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接