Java的隐藏功能


295

看完C#的隐藏功能后,我想知道Java的一些隐藏功能是什么?


17
请注意,使用这些隐藏功能并不总是一个好主意。通常,它们使您感到惊讶,并使其他人难以理解您的代码。
Kevin Bourrillion,09年

1
您(/某人)应该像C#问题一样在问题正文中整齐地总结答案。
ripper234

Answers:


432

几个月前,Double Brace Initialization使我惊讶,以前从未听说过它。

ThreadLocals通常并不广为人知,它是一种存储每个线程状态的方法。

由于JDK 1.5 Java除了锁以外,还具有非常好的实现和健壮的并发工具,因此它们位于java.util.concurrent中,一个特别有趣的示例是java.util.concurrent.atomic子包,其中包含实现比较的线程安全原语。-and-swap操作,并且可以映射到这些操作的实际本机硬件支持的版本。


40
双括号初始化...很奇怪...但是我会警惕过分采用该特定习惯用法,因为它实际上创建了该对象的匿名子类,这可能导致令人困惑的equals / hashcode问题。java.util.concurrent是一个非常不错的软件包。
MB。

6
教过 Java,这是我第一次遇到这种语法...这表明您永不停止学习= 8
Yuval

49
请注意,如果您保留对使用此“双花括号”惯用语初始化的集合的引用(或者,如果我们通过其实名来调用它-具有初始化程序块的匿名类),则隐式持有对外部对象的引用,这可能会导致讨厌的内存泄漏。我建议完全避免。
ddimitrov

51
“双括号初始化”是一个非常委婉的名称,用于创建一个匿名内部类,掩盖实际发生的事情,听起来好像内部类打算以这种方式使用。这是我希望保持隐藏的模式。
erickson

11
几乎,它实际上不是一个静态块,而是一个“初始化程序块”,它有所不同,因为它在不同的时间执行(请参阅我在答案中输入的链接以获取更多详细信息)
Boris Terzic,2009年

279

类型参数方差的联合并集:

public class Baz<T extends Foo & Bar> {}

例如,如果您想使用一个同时为Comparable和Collection的参数:

public static <A, B extends Collection<A> & Comparable<B>>
boolean foo(B b1, B b2, A a) {
   return (b1.compareTo(b2) == 0) || b1.contains(a) || b2.contains(a);
}

如果两个给定的集合相等或其中任何一个包含给定的元素,则此人为设计的方法将返回true,否则返回false。需要注意的是,您可以在参数b1和b2上调用Comparable和Collection的方法。


我最喜欢的用法是当您需要一种接受附加字符序列的方法时。
尼尔·科菲

5
是否可以在其中使用“ OR”而不是&?
mainstringargs

9
@Grasper:否,在此上下文中未提供OR(不交集联合)。但是您可以改用像Either <A,B>这样的不相交的并集数据类型。此类型是Pair <A,B>类型的对偶。请查看Functional Java库或Scala核心库以获取此类数据类型的示例。
Apocalisp

5
您应该说您必须只扩展一个类和多个接口->公共类Baz <T扩展Clazz&Interface1&InterfaceI ...,而不是类Baz <T扩展Clazz1&ClazzI>
JohnJohnGa 2011年

220

前几天,我对实例初始化器感到惊讶。我删除了一些代码折叠的方法,最终创建了多个实例初始化器:

public class App {
    public App(String name) { System.out.println(name + "'s constructor called"); }

    static { System.out.println("static initializer called"); }

    { System.out.println("instance initializer called"); }

    static { System.out.println("static initializer2 called"); }

    { System.out.println("instance initializer2 called"); }

    public static void main( String[] args ) {
        new App("one");
        new App("two");
  }
}

执行该main方法将显示:

static initializer called
static initializer2 called
instance initializer called
instance initializer2 called
one's constructor called
instance initializer called
instance initializer2 called
two's constructor called

我想如果您有多个构造函数并需要通用代码,这些将很有用

他们还提供语法糖来初始化您的课程:

List<Integer> numbers = new ArrayList<Integer>(){{ add(1); add(2); }};

Map<String,String> codes = new HashMap<String,String>(){{ 
  put("1","one"); 
  put("2","two");
}};

38
相对于需要调用的显式方法,此方法的优点在于,如果以后有人添加构造函数,则无需记住调用init()。这将自动完成。这样可以防止将来的程序员出错。
Shiny先生和新安宇

40
而且,与init()方法不同,它可以初始化final字段。
达伦(Darron)

2
如果您扩大班级并实例化各个孩子该怎么办?它仍然会以相同的方式运行吗?
Kezzer

12
人们经常取消认证(例如stackoverflow.com/questions/281100/281127#281127),尤其是对其技术优点提出质疑。但是,如果这里有更多的程序员研究了SCJP,那么许多人就不会将其视为“隐藏功能”。;-)
Jonik

12
我敢打赌“ 24小时内使用Java”一书也有这个“明显的功能”。阅读更多内容:)(
Özgür'09年

201

JDK 1.6_07 +包含一个名为VisualVM(bin / jvisualvm.exe)的应用程序,它是许多工具之上的漂亮GUI。似乎比JConsole更全面。


它有一个插件(它是一个netbeans东西),允许它使用Jconsole插件。相当不错。
托尔比约恩Ravn的安徒生

实际上,VisualVM是切成薄片以来最好的东西!不幸的是,在针对JDK 1.5运行时,它没有所有功能
sandos 2010年

我发现VisualVM在某些情况下运行缓慢或无法使用。商业化的YourKit没有这个问题,但是不幸的是不是免费的。
Roalt

来自JDK 1.6.0_22和更高版本的Visual VM的最新版本已得到很大改进。我敢打赌JDK1.7会有更好的版本。
djangofan 2011年


156

对于大多数人来说,我在Java开发人员职位上被标记为区块的采访非常令人惊讶。这是一个例子:

// code goes here

getmeout:{
    for (int i = 0; i < N; ++i) {
        for (int j = i; j < N; ++j) {
            for (int k = j; k < N; ++k) {
                //do something here
                break getmeout;
            }
        }
    }
}

谁说过gotoJava只是关键字?:)


2
好吧,我宁愿选择一种方式来做。例如,我看到人们在使用System.exit(1); 在Servlet和EJB代码中,但这并不意味着我们应该删除System.exit();。来自JDK,对吧?
Georgy Bolyuba

31
在某些情况下,在嵌套循环构造中,继续进行下一个外部循环迭代可能会很有用。这将是对此功能的合理使用。
alasdairg

75
许多程序员(甚至可能也是)特别未知的是,您实际上可以标记并突破任何旧块。不必一定是循环-您可以定义一些任意块,给它一个标签,然后使用break。
尼尔·科菲

27
它根本不是goto,它只能返回到先前的迭代(即:您不能向前跳)。这与迭代返回false时发生的机制相同。说Java具有goto就像在说任何其编译器生成JUMP指令的语言都具有goto语句。
Zombies

4
因此,您基于Java琐事而不是基于解决问题和通过设计思考的能力进行采访。我将确保我从不采访您的公司。:)
Javid Jamae

144

从JDK 1.5开始,协变量返回类型如何?由于它不是很性感,所以它的宣传很少,但是据我所知,它是泛型工作必不可少的。

本质上,编译器现在允许子类将覆盖方法的返回类型缩小为原始方法的返回类型的子类。因此,这是允许的:

class Souper {
    Collection<String> values() {
        ...
    }
}

class ThreadSafeSortedSub extends Souper {
    @Override
    ConcurrentSkipListSet<String> values() {
        ...
    }
}

您可以调用子类的values方法,并获得一个安全SetStrings 排序线程,而不必向下转换为ConcurrentSkipListSet


您能否提供示例用法?
Allain Lalonde

24
我经常使用。clone()是一个很好的例子。它应该返回Object,这意味着您必须说例如(List)list.clone()。但是,如果您声明为List clone(){...},则无需进行强制类型转换。
杰森·科恩

142

在finally块中进行控制转移会丢弃任何异常。以下代码不会引发RuntimeException -它会丢失。

public static void doSomething() {
    try {
      //Normally you would have code that doesn't explicitly appear 
      //to throw exceptions so it would be harder to see the problem.
      throw new RuntimeException();
    } finally {
      return;
    }
  }

来自http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html


7
这很讨厌,但这也只是最终运作方式的逻辑结果。try / catch / finally流控制可以执行预期的操作,但只能在特定限制内进行。同样,您必须小心,不要在catch / finally块内引起异常,否则也将丢弃原始异常。如果在try块内执行System.exit(),则不会调用finally块。如果打破正常流程,就会打破正常流程...
Neil Coffey

最终不要使用{return; },但最终{没有返回的代码}。这是合乎逻辑的,因为最终也打算在发生异常时执行,并且作为异常处理程序返回的唯一可能含义必须是忽略异常,并且实际上是返回。
Extraneon

21
这似乎比隐藏功能更像是一个“陷阱”,尽管有很多方法可以将其用作隐藏功能,但是使用此方法并不是一个好主意。
davenpcj

如果执行此操作,Eclipse将发出警告。我在Eclipse。如果要捕获异常...则捕获异常。
helios 2010年

这就是您为从方法中间返回的脏代码支付的费用。但仍然是一个很好的例子。
Rostislav Matl 2010年

141

尚未见任何人提到instanceof以不需要检查null的方式实现。

代替:

if( null != aObject && aObject instanceof String )
{
    ...
}

只需使用:

if( aObject instanceof String )
{
    ...
}

9
可惜的是,这是一个鲜为人知的功能。我已经看过很多类似于第一段代码的代码。
彼得·多尔伯格

4
这是因为Java具有一个您看不到或无法引用的特殊(隐藏)空类型。
Nick Hristov

更糟糕的是在C / C ++中使用freeing或deleteing 之前检查null 。这样的基本概念。
Thomas Eding

134

枚举中允许方法和构造函数令我惊讶。例如:

enum Cats {
  FELIX(2), SHEEBA(3), RUFUS(7);

  private int mAge;
  Cats(int age) {
    mAge = age;
  }
  public int getAge() {
    return mAge;
   }
}

您甚至可以拥有一个“常量特定类主体”,该主体允许特定的枚举值覆盖方法。

更多文档在这里


20
实际上,它确实很棒,它使枚举成为OO,并以非常干净的方式解决了许多初始化问题。
Bill K

5
枚举为单例吗?枚举只有一个值?
Georgy Bolyuba,

6
乔治:单例是对象的一个​​实例,而不是具有一个值的对象。
dshaw

20
@Georgy:另请参见Joshua Bloch的Effective Java(第二版)中的第3项;“虽然这种方法尚未得到广泛采用,但是单元素枚举类型是实现单例的最佳方法。”
Jonik

3
小nitpick:mAge应该是最终的。枚举很少有非最终形式的理由。
Joachim Sauer

121

泛型方法的类型参数可以如下明确指定:

Collections.<String,Integer>emptyMap()

10
天哪,这是丑陋而混乱的。与类型安全无关。
克里斯·布罗德富特

8
我喜欢这个。它使您的代码更加明确,对于需要维护一两年的可怜的草皮来说,代码也更加清晰。
extraneon

6
在声明了静态通用方法(例如)的情况下,这实际上非常有用public static <T> T foo(T t)。然后,您可以致电Class.<Type>foo(t);
Finbarr 2010年

由于某种原因,这似乎不适用于静态导入的方法。.我想知道为什么。
oksayt 2011年

这在将三元ifs与返回值一起使用时特别有用。例如return set1.equals(set2) ? new ArrayList<String>(set1) : Collections.<String>emptyList()。对于某些方法调用(其中简单的Collections.emptyMap()会给出编译错误),它也很有用。
Andreas Holstenson 2011年

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方法,我可以定义一个内置的(五个)集合。


27
这太疯狂了。(+1)
头足类动物

12
@Arian,这不是疯子。这个。是。JAVAAAAAAHHHH!
slezica 2011年

1
WHAAAAAT不,我和Adrian在一起。这不是Java。这太疯狂了。我很想用这个。
slezica 2012年

104

从Java 1.5开始,Java现在具有更简洁的语法来编写可变arity函数。因此,现在您不仅可以传递数组,还可以执行以下操作

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

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


23
重要的是,在调用方法时,您可以编写:foo(“ first”,“ second”,“ third”)
史蒂夫·阿姆斯特朗

9
这样就可以改写旧的世界了 公共静态无效main(String ... args){System.out.println(“ H​​ello World!”); }
Karussell 2010年

@Karussell也许吧,但论点似乎并不相关:p
Kelly Elton

93

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

Windows:CTRL-Break在您的Java cmd /控制台窗口中

Unix: kill -3 PID


15
在Unix中也是ctrl- \。或使用JDK中的jstack。
汤姆·霍顿

9
谢谢,您刚刚教我我的键盘有一个Break键。
艾米B 2010年

2
在Windows上,只有在当前控制台窗口中正在运行进程的情况下,CTRL-BREAK才起作用。您可以改用JAVA_HOME / bin / jstack.exe。只需为其提供Windows进程ID。
贾维德(Javid Jamae)2010年

我以为那是杀人-SIGQUIT
Nick

@Nick,是的,SIGQUIT通常是信号3。
克里斯·马佐拉

89

有人发布了有关实例初始化程序的信息,这是一个很好的用法:

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

如果您只是在做快速简单的事情,这是一种初始化地图的快速方法。

或使用它来创建快速摆架原型:

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

不知何故,好像在Java中添加了“ with”关键字(实际上是功能)。可能非常方便,最近我苦恼,因为Collections不能使用数组的初始化。谢谢!
PhiLho

15
但是,使用此功能有一个副作用。创建匿名对象,这可能并不总是很好。
艾米特

17
尽管经过更多研究,我不得不说我奇怪地被它提供的自然嵌套所吸引,甚至是“滥用”版本。
比尔K 2009年

4
是的-我非常喜欢“滥用”版本,我认为它非常清晰易读,但也许就是我。
巴里

3
完全同意,反映gui层次结构的代码层次结构是对一系列方法调用的巨大改进。
opsb

88

动态代理(在1.3中添加)允许您在运行时定义符合接口的新类型。它派上用场了很多次。


10
动态代理是选择编写Foo接口并在默认“ FooImpl”类中使用该接口的重要原因。乍一看似乎很丑陋(“为什么不只有一个叫做Foo的类?”),但是就单元测试的未来灵活性和可模拟性而言,好处是很方便的。尽管也有方法可以对非接口执行此操作,但它们通常需要额外的东西,例如cblib。
达里安(Darien)2010年

82

最终的初始化可以推迟。

它确保即使在逻辑流程复杂的情况下,也始终会设置返回值。遗漏案例并意外返回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;
}

真令人惊讶 不管设置在哪里出现,都可以公平地说“最终变量的值可以设置一次”吗?
David Koelle,

29
是的,但更重要的是:“最终变量的值必须设置一次”
Allain Lalonde

6
+1同意,这是在编译时发现错误的另一种有价值的工具,程序员出于某种原因似乎不愿使用该工具。请注意,由于从Java 5开始,'final'也具有线程安全性,因此在构造函数期间设置final变量非常宝贵。
尼尔·科菲

4
尽管对于这种特定方法,我只会使用多个返回值。实际上,在大多数情况下,我可能会将其重构为单独的方法并使用多个返回值。
ripper234

我喜欢这个!我总是删除final关键字,因为我认为它会失败。谢谢!
KARASZIIstván10年

62

我认为Java的另一个“被忽略”功能是JVM本身。它可能是最好的虚拟机。它支持许多有趣且有用的语言(Jython,JRuby,Scala,Groovy)。所有这些语言都可以轻松无缝地协作。

如果您设计一种新的语言(例如在scala案例中),您将立即拥有所有现有的库,因此您的语言从一开始就是“有用的”。

所有这些语言都使用HotSpot优化。VM非常易于监视和调试。


18
不,它实际上不是一个很好的虚拟机。它是专门为运行JAVA设计的。无类型的动态和功能语言不能很好地与它配合使用。要使用VM,您应该使用.NET / Mono。旨在与
每种

14
实际上,JVM专为运行Java字节码而设计。您可以将大多数现代语言编译为Java字节码。关于Java字节码唯一缺少的是动态语言支持,指针和尾部递归支持。
mcjabberz

12
@ Hades32:.NET VM实际上与JVM非常相似。它只是在最近才获得了对动态语言的支持(使用DLR),而Java 7也将获得这种支持。.NET的经典“每种语言”(C#,Visual Basic.NET等)都具有几乎完全相同的功能集。
约阿希姆·绍尔

13
JVM不支持泛型,而.NET VM则支持。JVM远非最佳。
布林迪

3
不要轻视对JVM不直接支持的特定语言功能的抱怨……但是我倾向于认为稳定性,跨平台一致性和良好的性能远远超出了JVM获得加分的原因。我已经在许多平台(包括AS / 400)上使用服务器端Java多年了,并且能够完全忘掉它-这些错误几乎总是在我可以修复的代码中,而且根本不会崩溃。
罗伯·惠兰

58

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

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

@Vuntic-它确实允许您在需要的上下文中定义一个简单的类。
ChaosPandion

1
@混沌,但是为什么呢?有一个实际的例子有用吗?
托尔比约恩Ravn的安德森

10
@Wouter-在这种情况下,start()在子类中实际上没有定义在匿名对象()上调用的方法...
Axel

实际上,如果您扩展一个基类进行一些必要的设置,调用您编写的方法然后进行拆卸的话,这是一个非常有用的功能。通过在基类中调用一个方法来开始事情(我可能不会给出相同的名称)。这里有一个例子使用(不是定义)在这里
AmigoNico

56

中的asList方法java.util.Arrays可以很好地结合使用varargs,通用方法和自动装箱:

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

15
您想用List构造函数包装返回的列表,否则int将是固定大小的(因为它由数组支持)
KitsuneYMG

2
Arrays.asList有可以不寻常的特征set()元素,但没有add()remove()。因此我通常将其包装在new ArrayList(...)或中Collections.unmodifiableList(...),具体取决于我是否希望列表可修改。
Christian Semrau

53

使用这个关键字从内部类访问包含类的字段/方法。在下面的示例中,我们想要使用匿名内部类中容器类的sortAscending字段。使用ContainerClass.this.sortAscending代替this.sortAscending可以解决问题。

import java.util.Comparator;

public class ContainerClass {
boolean sortAscending;
public Comparator createComparator(final boolean sortAscending){
    Comparator comparator = new Comparator<Integer>() {

        public int compare(Integer o1, Integer o2) {
            if (sortAscending || ContainerClass.this.sortAscending) {
                return o1 - o2;
            } else {
                return o2 - o1;
            }
        }

    };
    return comparator;
}
}

4
仅当阴影名称(在您的情况下,使用方法参数名称)时,这才是必需的。如果您将参数称为其他名称,则无需使用“ this”就可以直接访问Container类的sortAscending成员变量。
sk。

7
引用封闭类仍然很有用,例如。如果您需要将其传递给某种方法或构造方法。
PhiLho

通常用于Android布局开发中,以便使用来从(例如)按钮的侦听器获取Context MyActivity.this
espinchi 2011年

52

并不是真正的功能,而是我最近在某些网页中发现的有趣技巧:

class Example
{
  public static void main(String[] args)
  {
    System.out.println("Hello World!");
    http://Phi.Lho.free.fr

    System.exit(0);
  }
}

是有效的Java程序(尽管会生成警告)。如果您不明白为什么,请参阅格雷戈里的答案!;-)好吧,这里的语法高亮也给出了提示!


15
整齐,带有注释:)标签
托尔比约恩Ravn的安德森

46

这并不是完全“隐藏的功能”,也不是很有用,但是在某些情况下可能非常有趣:
类sun.misc.Unsafe-将允许您在Java中实现直接内存管理(您甚至可以编写带有以下内容的自修改Java代码:如果您尝试了很多,可以这样做):

public class UnsafeUtil {

    public static Unsafe unsafe;
    private static long fieldOffset;
    private static UnsafeUtil instance = new UnsafeUtil();

    private Object obj;

    static {
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);

            unsafe = (Unsafe)f.get(null);
            fieldOffset = unsafe.objectFieldOffset(UnsafeUtil.class.getDeclaredField("obj"));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    };
}

20
这是一个阳光* API,它是不是真的本身的Java语言的一部分。
DW。

在Unsafe上还有许多其他奇怪的方法,例如创建对象而不调用构造函数,malloc / realloc / free样式方法。
彼得·劳瑞

我特别喜欢内存位置上的原始getter和setter,例如putDouble(long address,double d)。
丹尼尔(Daniel)

42

当在Swing我喜欢隐藏的工作Ctrl- Shift- F1功能。

它转储当前窗口的组件树。
(假设您尚未将该按键绑定到其他东西。)


1
您的窗口管理器很可能具有与该键绑定的内容。Gnome没有绑定到它,所以我假设您正在运行KDE,它将它绑定到“切换到桌面13”。您可以通过以下方法进行更改:转到“控制面板”,“区域”,“键盘快捷键”并删除Shift-Ctrl-F1
Devon_C_Miller

40

每个类文件均以十六进制值0xCAFEBABE开头以将其标识为有效的JVM字节码。

说明


38

我的投票投给java.util.concurrent及其并发集合和灵活的执行程序,其中包括线程池,计划任务和协调任务。DelayQueue是我个人的最爱,其中元素在指定的延迟后可用。

java.util.Timer和TimerTask可以安全地停下来。

另外,不是完全隐藏,而是与其他与日期和时间相关的类位于不同的包中。在纳秒,微秒,毫秒和秒之间进行转换时,java.util.concurrent.TimeUnit非常有用。

它的读取结果比通常的someValue * 1000或someValue / 1000好得多。


最近发现CountDownLatchCyclicBarrier- 这么有用!
拉斐尔2012年

37

语言级别的assert关键字。


19
assert的问题在于,它需要在运行时打开。
Extraneon

10
但是,如果禁用它,就好像它不存在一样。您可以在代码中添加任意数量的断言,并且禁用它们不会对性能造成任何影响。
拉维·瓦劳

5
我认为断言是一件好事:可以将其关闭而不会受到惩罚。
andref

问题是,如果您不小心在断言中实现了副作用,则必须打开断言才能使您的程序正常工作...
Chii

要检测断言是否打开,可以使用{boolean assertsOn = false; 断言assertsOn = true; if(assertsOn){/ *复杂验证* /}}。如果assert状态不是预期的,这还允许记录或引发异常。
fernacolo 2011年


36

在1.5中增加了for-each循环构造。我<3。

// For each Object, instantiated as foo, in myCollection
for(Object foo: myCollection) {
  System.out.println(foo.toString());
}

并可以在嵌套实例中使用:

for (Suit suit : suits)
  for (Rank rank : ranks)
    sortedDeck.add(new Card(suit, rank));

for-each构造也适用于数组,其中它隐藏索引变量而不是迭代器。以下方法返回int数组中的值之和:

// Returns the sum of the elements of a
int sum(int[] a) {
  int result = 0;
  for (int i : a)
    result += i;
  return result;
}

链接到Sun文档


30
我认为i这里使用超级混乱,因为大多数人期望我是索引而不是数组元素。
cdmckay,2009年

所以... int sum(int [] array){int result = 0; for(int element:array){结果+ =元素; 返回结果;}
Drew

28
唯一令我烦恼的是,创建用于访问循环计数值的关键字确实非常容易,但您不能这样做。如果我想遍历两个数组并根据第一个数组中的值对第二个数组进行更改,我将不得不使用旧语法,因为我没有第二个数组的偏移量。
杰里科

6
遗憾的是,它也无法与Enumerations一起使用,就像JNDI中使用的那样。回到那里的迭代器。
Extraneon

3
@extraneon:看一下Collections.list(Enumeration <T> e)。这应该有助于在foreach循环中迭代枚举。
Werner Lehmann 2010年

34

我个人发现java.lang.Void得很晚-与泛型一起提高了代码的可读性,例如Callable<Void>


2
不完全的。在某些时候,您需要具体说明:Executors.newSingleThreadExecutor()。submit(new Callable <Void>(){..})-您无法实例化新的Callable <?>(),需要指定一个显式类型-因此,它是Callable <Object>的替代方法。
RahelLüthy09年

4
Void比Object更具体,因为Void只能为null,Object可以为任何对象。
彼得·劳瑞
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.