如何修复这些双括号[重复]

Posted

技术标签:

【中文标题】如何修复这些双括号[重复]【英文标题】:How do I fix these double braces [duplicate] 【发布时间】:2018-08-23 05:18:47 【问题描述】:

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

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

【问题讨论】:

我意识到这是一种罪过,我应该解决这个问题。如果您不知道如何“解决”它,您是如何意识到这一点的? 我正在使用 IntelliJ,它已引发自动警告。在问这个问题之前,我自己进行了一些研究,我知道这可能导致的问题,但大多数解决方案似乎都没有涵盖这种类型。我正在尝试应用我的知识,但我似乎无法解决这个问题。 @蒂姆 我仍然不确定如何在不了解其用途的情况下识别此语法的问题。我假设您不理解其目的,因为如果您理解了,您还会意识到将其重写为“更简单”的代码是多么简单 看看Double Brace Initialisation - 这可能不是罪过。 @OldCurmudgeon 查看Why you shouldn't use the double brace initializer,了解为什么它通常不是一个好主意。长话短说:内部匿名类和对Outer.this 的隐式引用以及它们可能导致的所有有趣的内存泄漏。 【参考方案1】:

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

    Anonymous sub-classes Instance initializer blocks

如何修复它的 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 将是“类名”,如果你可以这样称呼它)将引用封闭的MyClass 实例。在某些情况下,这可能没问题。但是,如果您创建notifyTypeItem 的目的是将其传递给其他东西并丢弃您的MyClass 实例,那么您将在应用程序中创建内存泄漏。 MyClass 实例将被MyClass$1 实例引用,SelectItem 将引用MyClass$1 实例,因此在SelectItem 实例不再被引用之前,MyClass 实例永远不会被垃圾回收。如果MyClass 除了SelectItem 之外还有其他几个引用,那么这只会增加单个MyClass 实例消耗的总内存,并导致更多的内存泄漏问题。


参考文献

以下是一些相关链接:

Anonymous Classes Java Trail(Java 跟踪,docs.oracle.com) Initializing Fields Java Trail(Java 跟踪,docs.oracle.com) What is Double Brace initialization in Java?(所以问题,***.com) Why you shouldn't use the double brace initializer(Nish Tahir 的博文,blog.nishtahir.com) When exactly is it leak safe to use (anonymous) inner classes?(所以问题,***.com)

【讨论】:

notifyItemType 正在传递,因此 Class 实例正在被删除。此代码导致内存泄漏。我将继续阅读此内容,但您已经打开了我的视野。谢谢

以上是关于如何修复这些双括号[重复]的主要内容,如果未能解决你的问题,请参考以下文章

Android,如何裁剪修复图像视图[重复]

JavaScript IE6双边缘错误/重复字符错误修复使用jQuery

如何修复双编码 UTF8 字符(在 utf-8 表中)

将空值作为参数传递给方法时如何修复 NullPointerException [重复]

Java:如何修复多种方法中的代码重复?

如何修复警告:初始化程序周围缺少大括号?