【问题标题】:How can I create a static final java.net.URL?如何创建静态最终 java.net.URL?
【发布时间】:2012-01-13 20:41:42
【问题描述】:

我的问题很简单。我正在尝试创建一组java.net.URLs,它们是public static final,以便任何类都可以从任何上下文访问它们,因为这些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()));
    }
}

如果你尝试编译它,它会告诉你因为第 3 行你不能。因此我的问题。

【问题讨论】:

    标签: java constructor static compiler-errors


    【解决方案1】:

    我更喜欢@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
        }
    }
    

    【讨论】:

    • @Supuhstar 我不担心这里的效率。通常,代码中还有许多其他效率低得多的部分,您通常并不关心,因为在大多数情况下更重要的是开发人员的生产力。
    • 以 Valve 为例:游戏开发者必须在严格的期限内完成,并且他们经常努力消除尽可能多的错误。通常,他们最初的 pre-alpha 版本的性能很差,因为他们希望尽快获得可测试的东西。然后他们针对目标平台进行优化,直到达到性能目标(比如每帧 30fps/34 毫秒)。一旦他们达到了那个目标,他们就不会为了快几毫秒而投入更多的精力,因为他们已经达到了他们的目标。他们不会优化优化最有可能没有好处的领域。
    • 从技术上讲,静态初始化的“最快”方式将是@HosamAly 提出的。但是,为了使其比我的解决方案更快 - 您需要在一个 try-catch 块内捆绑尽可能多的 URL 初始化。原因是 try-catch 操作有点耗费资源。因此,如果您对 each 变量使用 try-catch,它会比将它们全部捆绑到一个 try-catch 块中要慢一些。但是,我个人更喜欢清晰易懂的代码。在你实际尝试在一个 try-catch 块中初始化多个 URL 之后,你就会明白我的意思了。
    • 自发布此问题并接受答案以来的 5 年中,我决定将其作为公认的答案,因为它更易于理解且功能更强大。
    • @Supuhstar 骄傲呢? ;)
    【解决方案2】:

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

    注意:需要使用临时变量以避免两次分配给最终静态字段的编译错误。如果字段不是final,可以直接赋值。

    【讨论】:

    • 编译器会报错STATIC_URL还没有被初始化(因为你使用final)。
    • 编译器错误:variable STATIC_URL might not have been initialized.
    • 我也希望看到使用 java.net.URI 的建议。如果使用需要 URL 的库,请在此时使用 toURL() 方法。
    【解决方案3】:

    如果您确定要硬连线 URL。你确定吗? java.net.URL 是 JDK 中破坏最全面的类之一。关于用作“常量”,涉及 DNS 查找,并且它使用可变静态(尽管如果您安装了 SecurityManager,则由安全检查保护)。

    如果只有一个,静态初始化器应该没问题。

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

    再一次,没有空值!

    【讨论】:

    • +1 表示无空值。如果你的常量之一已经爆炸,那么继续下去真的没有意义。
    【解决方案4】:

    我编译它的唯一方法是删除 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,不,不会。此解决方案(上面发布)是唯一 可编译的解决方案。你的没有。我已经使用 IDE 和命令行编译过它,但你的失败了。
    • @Supuhstar,我不是“高高在上”。我只是发布了一个我测试过的代码,而不是仅仅为了点而急于发布答案。此外,SO 旨在提供有效的解决方案/答案,而不是贪婪。 :-)
    • 抱歉,当您说“我的解决方案是唯一有效的解决方案,所以您的解决方案不可能正确时,我只是假设您是在自命不凡"
    • @TheEliteGentleman Mine 使用 javac 1.6.0_26 编译。您使用的是哪个编译器版本?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多