2024-04-20 09:00:01

Java的隐藏特性

在阅读了c#的隐藏特性之后,我想知道Java的隐藏特性有哪些?


当前回答

部分功能,部分麻烦:Java的String处理使其“看起来”是原生类型(使用运算符,+,+=)

能写的:

String s = "A";
s += " String"; // so s == "A String"

非常方便,但只是语法糖(即被编译为):

String s = new String("A");
s = new StringBuffer(s).append(" String").toString();

因此,一个对象实例化和2个方法调用一个简单的连接。想象一下以这种方式在循环中构建一个长字符串!?并且StringBuffer的所有方法都声明为同步的。谢天谢地,在Java 5中,他们引入了StringBuilder,它与StringBuffer是一样的,只是没有同步。

这样的循环:

String s = "";
for (int i = 0 ; i < 1000 ; ++i)
  s += " " + i; // Really an Object instantiation & 3 method invocations!

可以(应该)在你的代码中重写为:

StringBuilder buf = new StringBuilder(); // Empty buffer
for (int i = 0 ; i < 1000 ; ++i)
  buf.append(' ').append(i); // Cut out the object instantiation & reduce to 2 method invocations
String s = buf.toString();

并将运行大约80+%比原来的循环! (在我运行的一些基准测试中高达180%)

其他回答

我喜欢

Javadoc的taglet和doclet使我们能够自定义Javadoc输出。 JDK工具:jstat, jstack等。

在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文档

The power you can have over the garbage collector and how it manages object collection is very powerful, especially for long-running and time-sensitive applications. It starts with weak, soft, and phantom references in the java.lang.ref package. Take a look at those, especially for building caches (there is a java.util.WeakHashMap already). Now dig a little deeper into the ReferenceQueue and you'll start having even more control. Finally grab the docs on the garbage collector itself and you'll be able to control how often it runs, sizes of different collection areas, and the types of algorithms used (for Java 5 see http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html).

前面已经提到,final数组可用于将变量传递给匿名内部类。

另一种更好、更简洁的方法是使用java.util.concurrent.atomic包中的AtomicReference(或AtomicBoolean/AtomicInteger/…)类。

这样做的好处之一是,这些类还提供了compareAndSet这样的方法,如果要创建几个可以修改同一个变量的线程,这个方法可能很有用。


另一个有用的相关模式:

final AtomicBoolean dataMsgReceived = new AtomicBoolean(false);
final AtomicReference<Message> message = new AtomicReference<Message>();
withMessageHandler(new MessageHandler() {
    public void handleMessage(Message msg) {
         if (msg.isData()) {
             synchronized (dataMsgReceived) {
                 message.set(msg);
                 dataMsgReceived.set(true);
                 dataMsgReceived.notifyAll();
             }
         }
    }
}, new Interruptible() {
    public void run() throws InterruptedException {
        synchronized (dataMsgReceived) {
            while (!dataMsgReceived.get()) {
                dataMsgReceived.wait();
            }
        }
    }
});

在这个特殊的例子中,我们可以简单地等待message变成非空,但是null通常是一个有效值,然后你需要使用一个单独的标志来完成等待。

上面的waitMessageHandler(…)是另一个有用的模式:它在某个地方设置了一个处理程序,然后开始执行可能抛出异常的Interruptible,然后在finally块中删除该处理程序,如下所示:

private final AtomicReference<MessageHandler> messageHandler = new AtomicReference<MessageHandler>();
public void withMessageHandler(MessageHandler handler, Interruptible logic) throws InterruptedException {
    synchronized (messageHandler) {
        try {
            messageHandler.set(handler);
            logic.run();
        } finally {
            messageHandler.set(null);
        }
    }
}

这里我假设messageHandler的handleMessage(…)方法在接收到消息时被另一个线程调用。messageHandler不能简单地为messageHandler类型:这样您将同步一个正在变化的变量,这显然是一个错误。

当然,它不需要是InterruptedException,它可以是IOException之类的东西,或者在特定代码段中有意义的任何东西。

Joshua Bloch的新书《Effective Java》是一个很好的资源。