在Java中使用匿名类被认为是好的风格还是不好的风格?

39

我知道匿名类在实现Listener等内容时可以节省打字。它们尝试替代某些使用闭包的情况。

但是社区对此语言特性的价值有何看法?它是否有意义并且您经常使用它?它是否使代码更清晰、更易懂和更易于维护?还是匿名类使代码难以阅读?

请分享您的观点,并准备好支持您观点的例子/论据。


请参考我的答案以获得更多澄清 https://dev59.com/HHNA5IYBdhLWcg3wQ7m4#35167249 - Gagandeep Singh
15个回答

31

在我不需要一个完整的类来执行某些任务的情况下,我倾向于使用匿名内部类。例如,如果我想要实现一个ActionListenerRunnable,但是我认为不需要内部类,那么使用匿名内部类可能会更加可读。例如,启动一个简单的Thread,使用匿名内部类可能更易于阅读:

public void someMethod()
{
    new Thread(new Runnable() {
        public void run()
        {
            // do stuff
        }
    }).start();
}
在某些情况下,例如上面的示例,它可以增加可读性,特别是对于一次性任务而言,因为要执行的代码都写在一个地方。使用内部类会“去除本地化”代码:
public void someMethod()
{
    new Thread(new MyRunnable()).start();
}

// ... several methods down ... //

class MyRunnable implements Runnable
{
    public void run()
    {
        // do stuff
    }
}

尽管如此,如果将会有相同的东西会被重复使用,那么它应该成为一个单独的类,无论是常规类还是内部类。

我倾向于在只是尝试代码而非实际应用程序的核心特性时,在程序中使用匿名内部类。


13

匿名内部类的另一个好处是,当你需要初始化像ArrayList和Set这样的集合时。这种做法也被称为双括号初始化。例如,

private static final Set<String> VALID_CODES = new HashSet<String>() {{
add("XZ13s");
add("AB21/X");
add("YYLEX");
add("AR2D");
}};

显然,这不仅局限于集合; 它可以用来初始化任何类型的对象 - 例如Gui对象:

 add(new JPanel() {{
setLayout(...);
setBorder(...);
add(new JLabel(...));
add(new JSpinner(...));
}});

这确实是非常好的语法糖。然而,它也有代价,而且这个代价超过了它的好处。根据Baeldung的说法,它被认为是一种反模式。 - Philzen

12

我认为使用匿名类会使代码变得不易读。但是在实现监听器时,匿名类是很有用的。在开发GWT应用程序时,匿名类是更好的选择。对于这些情况,如果我们不使用匿名类,则代码行数将增加。


6

我们经常使用匿名类。我发现它们很容易用于实现仅有一个或两个方法且功能没有在其他地方使用的接口。如果您在其他地方再次使用相同的功能,则应该有一个真正的类可供重用。


2
或者将匿名内部类及其周围的一些代码移动到单独的方法中。这样做可以使您的“API”更加简洁。 - Tom Hawtin - tackline

6
无论使用匿名类是否提高可读性都是一种口味问题。主要问题绝对不在这里。
像内部类一样,匿名类也携带对封闭类的引用,从而使没有它的非私有事物成为可能。简而言之,封闭类的this引用可能通过内部类逃逸。所以答案是:如果内部类公开自己,则使用内部类是非常糟糕的实践,因为那将自动发布封闭类。例如:
changeManager.register(new ChangeListener() {
    public void onChange(...) {
       ...
    }});

在这里,匿名的ChangeLstener被传递到ChangeManagerregister方法中。这样做将自动发布封闭的类。
这绝对是一种不好的做法。

3

我主要使用匿名类来实现只有一个方法的接口,例如RunnableActionListener。大多数较大的接口都需要它们自己的类或在已经存在的类中实现。而且这是我的观点,我不需要支持它的论据。


2

如果尽可能地限制范围和访问是一件好事,那么匿名类就非常好。它们的作用域仅限于需要它们的一个类。在适当的情况下,我认为匿名类很好。

一旦您复制相同的函数,它就变成了一个坏主意。将其重构为独立的公共类。具有重构功能的IDE使这变得容易。


但是私有内部类在作用域上也受限于其外部类。那么匿名类有什么优点呢? - Mnementh

2

匿名类在GUI应用程序中特别是事件处理中经常出现。匿名类在实现包含一个或两个方法的小接口的情况下非常有用。例如,您有一个类,其中有两个或三个线程,并且您想使用这些线程执行两个或三个不同的任务。在这种情况下,您可以借助匿名类来执行所需的任务。请看下面的示例:

class AnonymousClass{

public static void main(String args[]){


    Runnable run1=new Runnable(){

        public void run(){

            System.out.println("from run1");
        }

    };
    Runnable run2=new Runnable(){

        public void run(){

            System.out.println("from run2");
        }

    };
    Runnable run3=new Runnable(){

        public void run(){

            System.out.println("from run3");
        }

    };



    Thread t1=new Thread(run1);
    Thread t2=new Thread(run2);
    Thread t3=new Thread(run3);


    t1.run();t2.run();t3.run();

}
}

输出:

来自run1

来自run2

来自run3

在上面的代码片段中,我使用了三个线程来执行三个不同的任务。请注意,我创建了三个匿名类,这些类包含了运行方法的实现,以执行三个不同的小任务。


1

使用它们是有道理的,但你必须意识到底层正在发生什么。我只在需要一个非常特定的类来完成某些任务时才使用它们,而这些任务在其他地方都不需要。


1

这取决于你将它们与什么进行比较。我宁愿拥有它们也不愿意没有它们,但是我更希望能够向像Arrays.sort()这样的方法提供纯代码块,而不必显式地创建包含我的compare()实现的类。


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