我如何修复这些双括号

时间:2018-03-14 15:31:39

标签: java double-brace-initialize

您好我正在尝试整理一些代码,我偶然发现了一些双括号。我意识到这是一种罪,我应该解决这个问题。但是,我不知道从哪里开始。有人可以帮忙吗?

private SelectItem notifyTypeItem = new SelectItem();

notifyTypeItem.setTitle("Default Notification");
    notifyTypeItem.setWidth("100%");
    notifyTypeItem.setValueMap(new LinkedHashMap<String, String>() {{
                   put("0", "None");
                   put("1", "Subtle");
                   put("2", "Intrusive");
               }}
    );

1 个答案:

答案 0 :(得分:2)

要了解如何修复它,您应该首先了解它正在做什么。为此,您需要了解两件事:

  1. Anonymous sub-classes
  2. Instance initializer blocks
  3. TL;如何修复它的DR只是将那些put调用和初始化从setter中分离出来:

    Map<String, String> valueMap = new LinkedHashMap<String, String>();
    valueMap.put("0", "None");
    valueMap.put("1", "Subtle");
    valueMap.put("2", "Intrusive");
    notifyTypeItem.setValueMap(valueMap);
    

    继续阅读,了解发生了什么以及为什么它可能是一种不好的方法。

    匿名子类

    匿名类通常只是一个没有名称的类。例如,您可以创建类似Runnable的接口的匿名实例:

    Runnable r = new Runnable() {
        @Override
        public void run() {
            // Do something
        }
    };
    r.run(); // Does that something
    

    同样,您也可以创建抽象类和具体类的匿名实例。例如,创建ThreadLocal

    的匿名实例非常常见
    private static ThreadLocal<SimpleDateFormat> localIsoDateFormat = new ThreadLocal<SimpleDateFormat>() {
    
        @Override
        protected SimpleDateFormat initialValue() {
            return new SimpleDateFormat("yyyy-MM-dd");
        }
    }
    

    当您不需要一个完整的专用类来覆盖一个或两个方法时,这非常有用,类似于只使用一个方法创建接口的匿名实例。

    实例初始化程序块

    实例初始化程序块允许您在构造函数之外执行初始化程序。例如:

    public class MyClass {
    
        private final String s;
        {
            s = "My Class String";
        }
    
        public String getS() { return s; }
    }
    

    它本质上是构造函数的替身,而且它通常是不必要的,所以你很少看到它。它几乎总是可以移动到构造函数。

    结合他们

    你的例子结合了它们。它创建了LinkedHashMap的匿名子类,然后它也使用了初始化块。格式更正确,您的代码是:

    Map<String, String> map = new LinkedHashMap<>() {
        {
            put("0", "None");
            put("1", "Subtle");
            put("2", "Intrusive");
        }
    };
    

    它是LinkedHashMap的匿名实例,其中包含执行put调用的实例初始化程序块。

    为什么不好?

    出于同样的原因,您需要be careful creating anonymous classes:对封闭类实例的引用。

    匿名类因应用程序中的内存泄漏源而臭名昭着。您的代码似乎位于非static上下文中。这意味着您创建的匿名LinkedHashMap子类将隐含引用您的方法所在的类。例如,如果您的方法位于MyClass

    public class MyClass {
        private SelectItem notifyTypeItem = new SelectItem();
    
        public void foo() {
            notifyTypeItem.setTitle("Default Notification");
            notifyTypeItem.setWidth("100%");
            notifyTypeItem.setValueMap(new LinkedHashMap<String, String>() {{
                       put("0", "None");
                       put("1", "Subtle");
                       put("2", "Intrusive");
                   }}
            );
        }
    }
    

    新创建的LinkedHashMap子类(MyClass$1将是&#34;类名&#34;,如果你可以调用它这样的东西)将引用封闭的{{1实例。在某些情况下,这可能没问题。但是,如果您要创建MyClass并将其传递给其他内容并丢弃notifyTypeItem实例,那么您将在应用程序中创建内存泄漏。 MyClass实例将引用MyClass实例,MyClass$1将引用SelectItem实例,因此MyClass$1实例永远不会被垃圾回收不再引用MyClass实例。如果SelectItem除了MyClass之外还有其他几个引用,那么这只会增加单个SelectItem实例消耗的总内存,并导致更多的内存泄漏问题。

    参考

    以下是一些相关链接: