Java的隐藏功能

295

17
请注意,并不总是一个好主意使用这些隐藏的功能;往往会让阅读你代码的其他人感到惊讶和困惑。 - Kevin Bourrillion
1
你(/某人)应该像C#问题那样将答案整洁地总结在问题正文中。 - ripper234
100个回答

121

泛型方法的类型参数可以像这样明确指定:

Collections.<String,Integer>emptyMap()

10
这太丑陋和混乱了。而且跟类型安全也没有关联。 - Chris Broadfoot
8
我喜欢这个。它让你的代码更加明确,因此对于将来一两年必须维护它的可怜人来说更加清晰明了。 - extraneon
6
在你声明了一个静态的泛型方法,例如 public static <T> T foo(T t) 的情况下,这个技巧非常实用。你可以通过 Class.<Type>foo(t) 来调用它。 - Finbarr
由于某些原因,这似乎无法与静态导入的方法一起使用。我想知道为什么。 - oksayt
这在使用带有返回值的三元条件语句时特别有用。例如 return set1.equals(set2) ? new ArrayList<String>(set1) : Collections.<String>emptyList()。它还适用于某些方法调用,其中简单的Collections.emptyMap()会导致编译错误。 - Andreas Holstenson

112

你可以使用枚举类型来实现一个接口。

public interface Room {
   public Room north();
   public Room south();
   public Room east();
   public Room west();
}

public enum Rooms implements Room {
   FIRST {
      public Room north() {
         return SECOND;
      }
   },
   SECOND {
      public Room south() {
         return FIRST;
      }
   }

   public Room north() { return null; }
   public Room south() { return null; }
   public Room east() { return null; }
   public Room west() { return null; }
}

编辑: 多年以后...

我在这里使用了这个功能。

public enum AffinityStrategies implements AffinityStrategy {

https://github.com/peter-lawrey/Java-Thread-Affinity/blob/master/src/main/java/vanilla/java/affinity/AffinityStrategies.java

通过使用接口,开发人员可以定义自己的策略。使用 enum 可以定义一个内置的策略集合(共五个)。


12
@Arian 这不是疯狂。这就是——Java!!! - salezica
1
什么?不可能,我和Adrian一样。这不是Java,这是疯狂的。我迫不及待地想使用它。 - salezica

104

从Java 1.5开始,Java现在具有更清晰的语法来编写可变元数的函数。因此,现在你可以这样做,而不仅仅是传递一个数组:

public void foo(String... bars) {
   for (String bar: bars)
      System.out.println(bar);
}

bars将自动转换为指定类型的数组。这不是一个巨大的胜利,但仍然是一次胜利。


23
重要的是,在调用该方法时,你可以这样写:foo("第一个","第二个","第三个") - Steve Armstrong
9
旧的"Hello World"程序可以重写为:public static void main(String... args) { System.out.println("你好,世界!"); } - Karussell
@Karussell 或许是这样,但看起来这些论点都不相关 :p - Kelly Elton

93

我的最爱:将所有线程堆栈跟踪转储到标准输出。

Windows操作系统:在Java cmd/console窗口中按下Ctrl+Break

Unix操作系统:使用kill -3 PID命令。


15
在Unix中也可以使用ctrl-\,或者使用JDK中的jstack命令。 - Tom Hawtin - tackline
9
谢谢,您刚刚教会我我的键盘有一个“Break”键。 - Amy B
2
在Windows上,只有在当前控制台窗口中运行进程时,CTRL-BREAK才起作用。您可以使用JAVA_HOME/bin/jstack.exe代替。只需提供Windows进程ID即可。 - Javid Jamae
我以为它是 kill -SIGQUIT。 - Nick Hristov
@Nick,是的,SIGQUIT通常是信号#3。 - Chris Mazzola

89

有几个人发表了关于实例初始化器的帖子,以下是其良好使用的示例:

Map map = new HashMap() {{
    put("a key", "a value");
    put("another key", "another value");
}};

如果您只是进行简单快速的操作,那么这是初始化地图的快捷方式。

或者将其用于创建快速的Swing框架原型:

JFrame frame = new JFrame();

JPanel panel = new JPanel(); 

panel.add( new JLabel("Hey there"){{ 
    setBackground(Color.black);
    setForeground( Color.white);
}});

panel.add( new JButton("Ok"){{
    addActionListener( new ActionListener(){
        public void actionPerformed( ActionEvent ae ){
            System.out.println("Button pushed");
        }
     });
 }});


 frame.add( panel );

当然,它可以被滥用:
    JFrame frame = new JFrame(){{
         add( new JPanel(){{
               add( new JLabel("Hey there"){{ 
                    setBackground(Color.black);
                    setForeground( Color.white);
                }});

                add( new JButton("Ok"){{
                    addActionListener( new ActionListener(){
                        public void actionPerformed( ActionEvent ae ){
                            System.out.println("Button pushed");
                        }
                     });
                 }});
        }});
    }};

15
使用这个的一个副作用是会创建匿名对象,但这并不总是好的。 - amit
17
看得更仔细后,我不得不说我对自然的嵌套结构产生了奇怪的吸引力,即使是“被滥用”的版本也是如此。 - Bill K
4
是的 - 我非常喜欢“滥用”的版本,我认为那个非常清晰易读,但也许这只是我的观点。 - barryred
3
完全同意,代码的层次结构反映了界面的层次结构,这比一系列方法调用要好得多。 - opsb
我不喜欢这个,因为它让应用程序启动比Java本来就慢得更慢了。它创建了一个全然无用的HashMap子类。 - Daniel
显示剩余5条评论

88

动态代理(自1.3版本开始)允许您在运行时定义符合接口规范的新类型。它在很多情况下都非常有用。


10
动态代理是选择编写一个Foo接口并在各处使用带有默认"FooImpl"类的很好的理由。一开始可能看起来有点丑陋(“为什么不只是有一个叫做Foo的类?”),但未来灵活性和单元测试模拟的好处非常方便。虽然也有办法用于非接口类,但它们通常需要额外的工具,如cblib。 - Darien

81

最终初始化可以延迟。

它确保即使有复杂的逻辑流程,返回值也总是被设置的。很容易因疏忽而错过某种情况并意外返回null。这并不意味着不可能返回null,只是明确表明这是故意的:

public Object getElementAt(int index) {
    final Object element;
    if (index == 0) {
         element = "Result 1";
    } else if (index == 1) {
         element = "Result 2";
    } else {
         element = "Result 3";
    }
    return element;
}

29
是的,但更强调:“最终变量的值必须设置一次”。 - Allain Lalonde
6
+1 赞同,这是另一个有价值的工具,可以在编译时发现错误,但由于某些原因,程序员似乎不太愿意使用。请注意,从Java 5开始,“final”还具有线程安全性问题,能够在构造函数期间设置最终变量是非常宝贵的。 - Neil Coffey
4
针对这种特定的方法,我会使用多个返回语句。实际上,在大多数适用情况下,我可能会将其重构为一个单独的方法并使用多个返回语句。 - ripper234
这通常是代码异味的一种表现。如上所述,应该重构为使用守卫闭包(带有多个返回值)。如果像这样的块仅作为方法的一部分存在,则应将其提取到一个新方法中,并带有多个返回值。 - opsb
一些评论提到了多个返回值 -- 请注意,您可以通过省略最后的返回语句来获得与最终变量相同的好处。这样做可以确保所有情况都被处理(并返回适当的值),否则代码将无法编译。 - Rob Whelan
显示剩余2条评论

62

我认为 Java 中另一个被忽视的特性就是它本身的 JVM。它可能是目前最优秀的虚拟机,而且支持许多有趣和实用的语言(Jython、JRuby、Scala、Groovy)。所有这些语言都可以轻松无缝地协作。

如果你设计一种新语言(比如 Scala),你可以立刻使用所有现有的库,并且你的语言从一开始就是“有用”的。

所有这些语言都利用了 HotSpot 优化。该虚拟机非常易于监视和调试。


18
不,实际上它不是一个非常好的虚拟机。它只是为运行JAVA而设计的。无类型动态和函数式语言与它不兼容。如果你想使用虚拟机,应该使用.NET/Mono。它被设计成可与任何语言配合使用。 - Hades32
14
实际上,JVM 只是专门设计用于运行 Java 字节码。你可以将大多数现代语言编译为 Java 字节码。Java 字节码唯一缺少的东西就是动态语言支持、指针和尾递归支持。 - mcjabberz
12
@Hades32:实际上,.NET虚拟机与JVM非常相似。它仅在相对较近的时间内(通过DLR)支持动态语言,Java 7也即将获得该支持。而.NET的经典“EVERY language”(C#,Visual Basic.NET等)几乎完全具有相同的功能集。 - Joachim Sauer
13
JVM 不支持泛型,而 .NET 虚拟机支持。JVM 远不是最好的。 - Blindy
3
不忽略关于JVM没有直接支持特定语言功能的抱怨...但我倾向于认为,稳定性、跨平台一致性和良好性能远远是JVM获得额外加分的原因。我已经在许多平台上(包括AS/400)使用服务器端Java工作多年了,基本上可以完全忘记它的存在--bug几乎总是在我可以修复的代码中,并且它根本不会崩溃。 - Rob Whelan
显示剩余2条评论

58

您可以定义一个匿名子类,并直接调用其方法,即使它没有实现任何接口。

new Object() {
  void foo(String s) {
    System.out.println(s);
  }
}.foo("Hello");

@Vuntic - 它允许您在需要的上下文中定义一个简单的类。 - ChaosPandion
1
@Chaos,但为什么?有一个实际的例子可以说明它的用处吗? - Thorbjørn Ravn Andersen
10
在这种情况下,对匿名对象调用的方法(start())实际上并没有在子类中定义...... - Axel
实际上,如果您扩展了执行某些必要设置、调用您编写的方法,然后进行拆卸的基类,则这是一个非常有用的功能。通过调用基类中的方法(我可能不会给相同的名称)来启动该过程。这里有一个使用示例(而非定义)链接 - AmigoNico

56

java.util.Arrays 中的 asList 方法允许灵活使用可变参数、泛型方法和自动装箱:

List<Integer> ints = Arrays.asList(1,2,3);

15
你需要用 List 构造函数包装返回的列表,否则整数将是固定大小的(因为它是由数组支持)。 - KitsuneYMG
2
Arrays.asList 具有不同寻常的特性,即您可以 set() 元素但不能 add()remove()。因此,我通常会将其包装在 new ArrayList(...)Collections.unmodifiableList(...) 中,具体取决于我是否希望列表可修改。 - Christian Semrau

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