Java的隐藏功能

时间:2008-08-19 01:36:03

标签: java

阅读Hidden Features of C#后,我想知道,Java的一些隐藏功能是什么?

100 个答案:

答案 0 :(得分:432)

几个月前,当我第一次发现它时,{p> Double Brace Initialization让我感到意外,之前从未听说过它。

ThreadLocals通常不是广为人知的存储每线程状态的方法。

由于JDK 1.5 Java具有非常好的实现和强大的并发工具,而不仅仅是锁,它们存在于java.util.concurrent中,一个特别有趣的例子是java.util.concurrent.atomic子包,其中包含实现了compare-and-swap操作,可以映射到这些操作的实际本机硬件支持版本。

答案 1 :(得分: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的方法。

答案 2 :(得分: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");
}};

答案 3 :(得分:201)

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

答案 4 :(得分:173)

自Java 6以来的Classpath通配符。

java -classpath ./lib/* so.Main

而不是

java -classpath ./lib/log4j.jar:./lib/commons-codec.jar:./lib/commons-httpclient.jar:./lib/commons-collections.jar:./lib/myApp.jar so.Main

请参阅http://java.sun.com/javase/6/docs/technotes/tools/windows/classpath.html

答案 5 :(得分: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;
            }
        }
    }
}

谁说java中的goto只是一个关键字? :)

答案 6 :(得分:144)

从JDK 1.5开始,协变返回类型如何?它的宣传非常糟糕,因为它是一个不太常见的补充,但据我所知,泛型工作绝对是必要的。

本质上,编译器现在允许子类将重写方法的返回类型缩小为原始方法返回类型的子类。所以这是允许的:

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

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

您可以调用子类的values方法,并获得Set s 的已排序线程安全String,而无需向下投射到{{1} }。

答案 7 :(得分: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

答案 8 :(得分:142)

没有看到有人提到实现的实例是以不需要检查null的方式实现的。

而不是:

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

只需使用:

if( aObject instanceof String )
{
    ...
}

答案 9 :(得分:134)

在枚举中允许方法和构造函数让我感到惊讶。例如:

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

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

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

更多文档here

答案 10 :(得分:121)

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

Collections.<String,Integer>emptyMap()

答案 11 :(得分: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 :(得分:104)

从Java 1.5开始,Java现在有了更清晰的语法来编写变量arity的函数。因此,现在您可以执行以下操作,而不仅仅是传递数组

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

条自动转换为指定类型的数组。不是一场巨大的胜利,而是一场胜利。

答案 13 :(得分:93)

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

你的java cmd / console窗口中的

windows: CTRL - Break

unix:kill -3 PID

答案 14 :(得分: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");
                        }
                     });
                 }});
        }});
    }};

答案 15 :(得分:88)

Dynamic proxies(在1.3中添加)允许您在运行时定义符合接口的新类型。它的出现次数惊人。

答案 16 :(得分: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;
}

答案 17 :(得分:62)

我认为java的另一个“被忽视的”特性是JVM本身。它可能是最好的VM。它支持许多有趣且有用的语言(Jython,JRuby,Scala,Groovy)。所有这些语言都可以轻松无缝地合作。

如果您设计了一种新语言(例如scala-case),您可以立即使用所有现有的库,因此您的语言从一开始就是“有用的”。

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

答案 18 :(得分:58)

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

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

答案 19 :(得分:56)

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

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

答案 20 :(得分:53)

使用 this 关键字访问内部类中包含类的字段/方法。在下面,相当人为的例子中,我们想要使用来自匿名内部类的容器类的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;
}
}

答案 21 :(得分:52)

不是一个真正的功能,但我最近在一些网页中发现了一个有趣的技巧:

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

    System.exit(0);
  }
}

是一个有效的Java程序(虽然它会生成警告)。 如果你不明白为什么,请看格雷戈里的回答! ;-)嗯,这里的语法高亮也给出了提示!

答案 22 :(得分: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);
        }
    };
}

答案 23 :(得分:42)

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

它转储当前窗口的组件树 (假设你没有把键击限制在别的东西上。)

答案 24 :(得分:40)

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

Explanation

答案 25 :(得分:38)

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

java.util.Timer和TimerTask可以安全地休息。

此外,还没有完全隐藏,但与其他与日期和时间相关的类不同。 java.util.concurrent.TimeUnit在纳秒,微秒,毫秒和秒之间转换时非常有用。

它比通常的someValue * 1000或someValue / 1000读得好很多。

答案 26 :(得分:37)

语言级断言关键字。

答案 27 :(得分:37)

并不是Java语言的一部分,但是Sun的JDK附带的javap反汇编程序并不广为人知或使用。

答案 28 :(得分:36)

在1.5中添加for-each循环结构。我&lt; 3 it。

// 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;
}

Link to the Sun documentation

答案 29 :(得分:34)

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

答案 30 :(得分:30)

也许最令人惊讶的隐藏功能是sun.misc.Unsafe类。

http://www.docjar.com/html/api/ClassLib/Common/sun/misc/Unsafe.java.html

你可以;

  • 在不调用构造函数的情况下创建对象。
  • 抛出任何异常甚至Exception而不用担心方法上的throws子句。 (我知道还有其他方法可以做到这一点)
  • 在不使用反射的情况下,在对象中获取/设置随机访问的字段。
  • 分配/释放/复制/调整大小可以长(64位)的内存块。
  • 获取对象中字段的位置或类中的静态字段。
  • 独立锁定和解锁对象锁。 (比如没有阻止的同步)
  • 根据提供的字节代码定义一个类。而不是类加载器确定字节代码应该是什么。 (你也可以用反射做到这一点)

顺便说一句:错误使用此类会导致JVM死机。我不知道哪个JVM支持这个类,所以它不可移植。

答案 31 :(得分:29)

这是我的清单。

我最喜欢的(也是最可怕的)隐藏功能是你可以从未声明抛出任何东西的方法中抛出已检查的异常。

import java.rmi.RemoteException;

class Thrower {
    public static void spit(final Throwable exception) {
        class EvilThrower<T extends Throwable> {
            @SuppressWarnings("unchecked")
            private void sneakyThrow(Throwable exception) throws T {
                throw (T) exception;
            }
        }
        new EvilThrower<RuntimeException>().sneakyThrow(exception);
    }
}

public class ThrowerSample {
    public static void main( String[] args ) {
        Thrower.spit(new RemoteException("go unchecked!"));
    }
}

你也可能想知道你可以抛出'null'......

public static void main(String[] args) {
     throw null;
}

猜猜这是什么打印:

Long value = new Long(0);
System.out.println(value.equals(0));

然后猜猜这回归:

public int returnSomething() {
    try {
        throw new RuntimeException("foo!");
    } finally {
        return 0;
    }
}

以上不应该让优秀的开发人员感到惊讶。


在Java中,您可以通过以下有效方式声明数组:

String[] strings = new String[] { "foo", "bar" };
// the above is equivalent to the following:
String[] strings = { "foo", "bar" };

因此,遵循Java代码是完全有效的:

public class Foo {
    public void doSomething(String[] arg) {}

    public void example() {
        String[] strings = { "foo", "bar" };
        doSomething(strings);
    }
}

是否有任何正当理由,相反,以下代码无效?

public class Foo {

    public void doSomething(String[] arg) {}

    public void example() {
        doSomething({ "foo", "bar" });
    }
}

我认为,上面的语法将是Java 5中引入的varargs的有效替代。并且,与之前允许的数组声明更加一致。

答案 32 :(得分:28)

Shutdown Hooks.这允许注册一个即时创建但仅在JVM结束时启动的线程!所以它是某种“全局jvm终结器”,你可以在这个线程中做出有用的东西(例如关闭像嵌入式hsqldb服务器这样的java资源)。这适用于System.exit(),或者使用CTRL-C / kill -15(但在unix上不能使用kill -9)。

此外,它很容易设置。

            Runtime.getRuntime().addShutdownHook(new Thread() {
                  public void run() {
                      endApp();
                  }
            });;

答案 33 :(得分:27)

值:

new URL("http://www.yahoo.com").equals(new URL("http://209.191.93.52"))

true

(来自Java Puzzlers)

答案 34 :(得分:26)

如果您进行了大量的JavaBean开发并使用了属性更改支持,那么通常最终会编写一个 lot 这样的setter:

public void setFoo(Foo aFoo){
  Foo old = this.foo;
  this.foo = aFoo;
  changeSupport.firePropertyChange("foo", old, aFoo);
}

我最近偶然发现了一个博客,该博客建议更简洁的实现,这使代码更容易编写:

public void setFoo(Foo aFoo){
  changeSupport.firePropertyChange("foo", this.foo, this.foo = aFoo);
}

它实际上简化了我能够在Eclipse中调整setter模板的程度,以便自动创建方法。

答案 35 :(得分:25)

静态导入以“增强”语言,因此您可以以类型安全的方式做好文字事物:

List<String> ls = List("a", "b", "c");

(也可以使用地图,数组,集合)。

http://gleichmann.wordpress.com/2008/01/13/building-your-own-literals-in-java-lists-and-arrays/

进一步说明:

List<Map<String, String>> data = List(Map( o("name", "michael"), o("sex", "male")));

答案 36 :(得分:23)

作为初学者,我非常欣赏Java 6中的JConsole监控软件,它已经为我解决了一些问题,并且我一直在寻找它的新用途。

显然JConsole已经存在于Java 5中,但我认为它现在已得到改进,至少现在工作得更稳定了。

Java 5中的JConsole: JConsole in Java 5

Java 6中的JConsole: JConsole in Java 6

当你在这里时,要好好看看系列中的其他工具: Java 6 troubleshooting tools

答案 37 :(得分:23)

不是那么隐蔽,但有趣。

你可以拥有一个没有main方法的“Hello,world”(它会抛出NoSuchMethodError想法)

最初由RusselW发表于Strangest language feature

public class WithoutMain {
    static {
        System.out.println("Look ma, no main!!");
        System.exit(0);
    }
}

$ java WithoutMain
Look ma, no main!!

答案 38 :(得分:23)

如果不使用默认初始值设定项,Java处理会对变量定义做一个巧妙的处理。

{
   int x;

   if(whatever)
      x=1;

   if(x == 1)
      ...
}

这将在编译时给您一个错误,即您有一个未正确定义X的路径。这对我有所帮助,我已经考虑过这样的默认初始化:

int x=0;
String s=null;

是一个糟糕的模式,因为它会阻止这种有用的检查。

那就是说,有时候很难绕过 - 我必须回去编辑= null,当它作为默认值有意义时,但我再也不会把它放在第一遍了。

答案 39 :(得分:21)

这不是一个隐藏的功能,但当我看到这个编译好的时候,它确实让我大吃一惊:

public int aMethod(){
    http://www.google.com
    return 1;
}

它编译的原因是编译器将行http://www.google.com“http:”部分视为标签,而其余部分是注释。

所以,如果你想编写一些古怪的代码(或混淆的代码),只需在那里放置很多http地址。 ; - )

答案 40 :(得分:20)

您可以在方法中声明一个类:

public Foo foo(String in) {
    class FooFormat extends Format {
        public Object parse(String s, ParsePosition pp) { // parse stuff }
    }
    return (Foo) new FooFormat().parse(in);

}

答案 41 :(得分:19)

他们花了足够长的时间来增加对此的支持,

System Tray

答案 42 :(得分:17)

我非常喜欢Java 1.6中重写的Threading API。 Callables很棒。它们基本上是具有返回值的线程。

答案 43 :(得分:17)

自我约束的泛型:

class SelfBounded<T extends SelfBounded<T>> {
}

http://www.artima.com/weblogs/viewpost.jsp?thread=136394

答案 44 :(得分:16)

可以使用该功能为基于Java控制台的应用程序显示启动画面。

使用命令行工具javajavaw选项-splash

例如:

java -splash:C:\myfolder\myimage.png -classpath myjarfile.jar com.my.package.MyClass

只要执行“com.my.package.MyClass”类

C:\myfolder\myimage.png的内容就会显示在屏幕的中央

答案 45 :(得分:16)

我喜欢静态导入方法。

例如,创建以下util类:

package package.name;

public class util {

     private static void doStuff1(){
        //the end
     }

     private static String doStuff2(){
        return "the end";
     }

}

然后像这样使用它。

import static package.name.util.*;

public class main{

     public static void main(String[] args){
          doStuff1(); // wee no more typing util.doStuff1()
          System.out.print(doStuff2()); // or util.doStuff2()
     }

}

Static Imports适用于任何课程,甚至数学......

import static java.lang.Math.*;
import static java.lang.System.out;
public class HelloWorld {
    public static void main(String[] args) {
        out.println("Hello World!");
        out.println("Considering a circle with a diameter of 5 cm, it has:");
        out.println("A circumference of " + (PI * 5) + "cm");
        out.println("And an area of " + (PI * pow(5,2)) + "sq. cm");
    }
}

答案 46 :(得分:16)

哦,我差点忘了这个小宝石。在任何正在运行的java进程上试试这个:

jmap -histo:live PID

您将获得给定VM中的实时堆对象的直方图。非常宝贵,可以快速识别某些类型的内存泄漏。我用来阻止它们的另一种技术是创建和使用所有集合类的大小有限的子类。这会导致易于识别的失控集合中的快速失败。

答案 47 :(得分:16)

List.subList返回原始列表中的视图

列表的文档但鲜为人知的特征。这允许您使用原始列表中镜像的更改来处理列表的各个部分。

列出subList(int fromIndex,int toIndex)

  

“此方法不需要显式范围操作(对于数组通常存在的排序)。任何需要列表的操作都可以通过传递subList视图而不是整个列表来用作范围操作。例如,以下习语从列表中删除了一系列元素:

       list.subList(from, to).clear();
     

可以为indexOf和lastIndexOf构造类似的习语,Collections类中的所有算法都可以应用于subList。“

答案 48 :(得分:15)

这不是一个真正的功能,但它让我轻笑, goto 是一个保留词,除了提示javac捅你的眼睛之外什么都不做。只是为了提醒你,你现在在OO-land。

答案 49 :(得分:15)

使用静态导入,你可以做很酷的事情:

List<String> myList = list("foo", "bar");
Set<String> mySet = set("foo", "bar");
Map<String, String> myMap = map(v("foo", "2"), v("bar", "3"));

答案 50 :(得分:15)

Javadoc - 当正确编写时(不幸的是一些开发人员的情况并非如此),它为您提供了一个清晰,连贯的描述代码应该做什么,而不是实际做什么。然后它可以变成一个很好的可浏览的HTML文档集。如果您使用持续集成等,则可以定期生成,以便所有开发人员都可以看到最新的更新。

答案 51 :(得分:14)

strictfp关键字。 (我从未在实际应用中看到它用过:)

您可以使用以下表示法获取基本类型的类:int.class, float.class等。做反射时非常有用。

最终数组可用于从匿名内部类“返回”值(警告,下面没用的示例):

final boolean[] result = new boolean[1];
SwingUtilities.invokeAndWait(new Runnable() {
  public void run() { result[0] = true; }
});

答案 52 :(得分:14)

您可以在匿名内部类上定义和调用方法。

他们不是那么隐藏,但是很少有人知道它们可以用来在类中定义一个新方法并像这样调用它:

(new Object() {
    public String someMethod(){ 
        return "some value";
    }
}).someMethod();

可能不是很常见,因为它也不是很有用,你可以在定义它时(或通过反射)调用的方法

答案 53 :(得分:13)

我知道Java 6包含脚本支持,但我最近才发现jrunscript, 它可以交互式地解释和运行JavaScript(以及一种假设,其他脚本语言,如Groovy),有点像Ruby shell中的Python shell或irb

答案 54 :(得分:13)

C-Style printf():)

System.out.printf("%d %f %.4f", 3,Math.E,Math.E);

输出: 3 2.718282 2.7183

二进制搜索(及其返回值)

int[] q = new int[] { 1,3,4,5};
int position = Arrays.binarySearch(q, 2);

与C#类似,如果在数组中找不到“2”,它会返回一个负值,但是如果你取得返回值的1的补码,你实际上得到的位置可以插入“2”。

在上面的例子中,position = -2,~position = 1这是应该插入2的位置...它还可以让你在数组中找到“最接近”的匹配。

我认为它非常漂亮......:)

答案 55 :(得分:12)

它并没有完全隐藏,但反射非常有用和强大。很高兴使用一个简单的Class.forName(“...”)。newInstance(),其中类类型是可配置的。编写这种工厂实现很容易。

答案 56 :(得分:12)

我知道这是在1.5版中添加的,但新的枚举类型是一个很棒的功能。不必使用旧的“int枚举模式”对我的一大堆代码有很大的帮助。 Check out JLS 8.9土豆上的甜汁!

答案 57 :(得分:12)

部分功能,部分麻烦:Java的字符串处理使其“显示”为本机类型(在它们上使用运算符,+,+ =)

能够写作:

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

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

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

为简单级联设置了一个Object实例和2个方法调用。想象一下,以这种方式在循环内构建一个长字符串!?并且所有StringBuffer的方法都声明为synchronized。值得庆幸的是(我认为)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%)

答案 58 :(得分:11)

我今天(重新)了解到,$是Java中方法或变量的合法名称。结合静态导入,它可以使一些稍微更易读的代码,具体取决于您的可读性:

http://garbagecollected.org/2008/04/06/dollarmaps/

答案 59 :(得分:11)

最终实例变量:

对于多线程代码非常有用,它使得讨论实例状态和正确性变得容易得多。在行业环境中没有看到太多,在java类中经常没有想到。


静态{something;}:

用于初始化静态成员(我也更喜欢静态方法来执行它(因为它有一个名字)。没想到。

答案 60 :(得分:10)

一种优化技巧,使您的代码更易于维护,并且不易受并发错误的影响。

public class Slow {
  /** Loop counter; initialized to 0. */
  private long i;

  public static void main( String args[] ) {
    Slow slow = new Slow();

    slow.run();
  }

  private void run() {
    while( i++ < 10000000000L )
      ;
  }
}

$ time java慢点 真实的0m15.397s
$ time java慢点 真正的0m20.012s
$ time java慢点 真正的0m18.645s

平均值:18.018s

public class Fast {
  /** Loop counter; initialized to 0. */
  private long i;

  public static void main( String args[] ) {
    Fast fast = new Fast();

    fast.run();
  }

  private void run() {
    long i = getI();

    while( i++ < 10000000000L )
      ;

    setI( i );
  }

  private long setI( long i ) {
    this.i = i;
  }

  private long getI() {
    return this.i;
  }
}

$ time java Fast
真正的0m12.003s
$ time java Fast
真正的0m9.840s
$ time java Fast
真正的0m9.686s

平均值:10.509秒

它需要更多的字节码来引用类范围变量而不是方法范围变量。在关键循环之前添加方法调用会增加很少的开销(并且调用可能会被编译器内联)。

此技术的另一个优点(始终使用访问器)是它消除了慢速类中的潜在错误。如果第二个帖子要将 i 的值连续重置为0(例如,通过调用slow.setI( 0 )),则类永远不会结束其循环。调用访问器并使用局部变量消除了这种可能性。

在Linux 2.6.27-14上使用J2SE 1.6.0_13进行测试。

答案 61 :(得分:10)

“const”是关键字,但您无法使用它。

int const = 1;   // "not a statement"
const int i = 1; // "illegal start of expression"

我想编译器编写者认为它将来可能会被使用,他们最好保留它。

答案 62 :(得分:10)

当您不需要StringBuilder中包含的同步管理时,请使用StringBuffer代替StringBuilder。它将提高您的应用程序的性能。

Java 7的改进甚至比任何隐藏的Java功能都要好:

  • 钻石语法: Link

不要使用那些无限的&lt;&gt; instanciation的语法:

Map<String, List<String>> anagrams = new HashMap<String, List<String>>();

// Can now be replaced with this:

Map<String, List<String>> anagrams = new HashMap<>();
  • 开关中的字符串: Link

在switch中使用String,而不是old-C int:

String s = "something";
switch(s) {
 case "quux":
    processQuux(s);
    // fall-through

  case "foo":
  case "bar":
    processFooOrBar(s);
    break;

  case "baz":
     processBaz(s);
    // fall-through

  default:
    processDefault(s);
    break;
}
  • 自动资源管理 Link

这段旧代码:

static void copy(String src, String dest) throws IOException {
    InputStream in = new FileInputStream(src);
    try {
        OutputStream out = new FileOutputStream(dest);
        try {
            byte[] buf = new byte[8 * 1024];
            int n;
            while ((n = in.read(buf)) >= 0)
                out.write(buf, 0, n);
        } finally {
            out.close();
        }
    } finally {
        in.close();
    }
}
现在可以用这个更简单的代码替换

static void copy(String src, String dest) throws IOException {
    try (InputStream in = new FileInputStream(src);
            OutputStream out = new FileOutputStream(dest)) {
        byte[] buf = new byte[8192];
        int n;
        while ((n = in.read(buf)) >= 0)
            out.write(buf, 0, n);
    }
}

答案 63 :(得分:9)

标识符可以包含外语字符,如变音符号:

而不是写作:

String title="";
有人可以写:

String Überschrift="";

答案 64 :(得分:9)

让我感到惊讶的是自定义序列化机制。

虽然这些方法是私有!! ,但在对象序列化过程中,JVM会“神秘地”调用它们。

private void writeObject(ObjectOutputStream out) throws IOException;
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;

通过这种方式,您可以创建自己的自定义序列化,使其更“无所不能”(安全,快速,稀有,简单等)

如果必须通过节点传递大量信息,这是真正需要考虑的事情。可以改变序列化机制以发送一半数据。很多时候瓶颈不在平台上,但通过电线发送的数量,可以在硬件中节省数千个dll。

这是一篇文章。 http://java.sun.com/developer/technicalArticles/Programming/serialization/

答案 65 :(得分:9)

您选择的编码中的属性文件怎么样?以前,当您加载属性时,您提供了一个InputStream,load()方法将其解码为ISO-8859-1。你可能实际上将文件存储在其他一些编码中,但是在加载到正确解码数据后你必须使用这样的令人作呕的黑客:

String realProp = new String(prop.getBytes("ISO-8859-1"), "UTF-8");

但是,从JDK 1.6开始,有一个load()方法接受Reader而不是InputStream,这意味着你可以从头开始使用正确的编码(还有一个store()方法一个作家)。这对我来说似乎是一件非常重要的事情,但它似乎一直没有大张旗鼓地进入JDK。几个星期前我偶然发现了它,并且只是一次提到谷歌的快速谷歌搜索。

答案 66 :(得分:9)

我可以添加Scanner对象。它是解析的最佳选择。

String input = "1 fish 2 fish red fish blue fish";
Scanner s = new Scanner(input).useDelimiter("\\s*fish\\s*");
System.out.println(s.nextInt());
System.out.println(s.nextInt());
System.out.println(s.next());
System.out.println(s.next());
s.close();

答案 67 :(得分:8)

大多数人都不知道他们可以克隆阵列。

int[] arr = {1, 2, 3};
int[] arr2 = arr.clone();

答案 68 :(得分:8)

Java 6中的注释处理API看起来非常透视代码生成和静态代码验证。

答案 69 :(得分:8)

当人们意识到可以使用反射调用私有方法和访问/更改私有字段时,人们有时会感到有些惊讶......

考虑以下课程:

public class Foo {
    private int bar;

    public Foo() {
        setBar(17);
    }

    private void setBar(int bar) {
        this.bar=bar;
    }

    public int getBar() {
        return bar;
    }

    public String toString() {
        return "Foo[bar="+bar+"]";
    }
}

执行此程序......

import java.lang.reflect.*;

public class AccessibleExample {
    public static void main(String[] args)
        throws NoSuchMethodException,IllegalAccessException, InvocationTargetException, NoSuchFieldException {
        Foo foo=new Foo();
        System.out.println(foo);

        Method method=Foo.class.getDeclaredMethod("setBar", int.class);
        method.setAccessible(true);
        method.invoke(foo, 42);

        System.out.println(foo);
        Field field=Foo.class.getDeclaredField("bar");
        field.setAccessible(true);
        field.set(foo, 23);
        System.out.println(foo);
    }
}

...将产生以下输出:

Foo[bar=17]
Foo[bar=42]
Foo[bar=23]

答案 70 :(得分:7)

您可以在初始化块和本地类的方法中访问最终的局部变量和参数。考虑一下:

    final String foo = "42";
    new Thread() {
        public void run() {
             dowhatever(foo);
        }
    }.start();

有点像关闭,不是吗?

答案 71 :(得分:7)

实际上,我喜欢Java的是有多少隐藏的技巧。这是一种非常明显的语言。这么多,经过15年,我能想到的几乎每一个都已列在这几页上。

也许大多数人都知道Collections.synchronizedList()会将同步添加到列表中。除非您阅读文档,否则您无法知道的是,您可以通过同步列表对象本身来安全地迭代该列表的元素。

某些人可能不知道CopyOnWriteArrayList,而Future代表了一种抽象多线程结果访问的有趣方法。

您可以通过各种管理,代理和附加API附加到VM(本地或远程),获取有关GC活动,内存使用,文件描述符甚至对象大小的信息。

虽然TimeUnit可能比long更长,但我更喜欢Wicket的Duration类。

答案 72 :(得分:7)

JDK发行版中bin目录中的JVisualVM。监视甚至分析任何Java应用程序,即使是没有使用任何特殊参数启动的应用程序。仅适用于最新版本的Java 6SE JDK。

答案 73 :(得分:7)

您可以对垃圾收集器以及它如何管理对象收集的强大功能非常强大,特别是对于长时间运行和时间敏感的应用程序。它从java.lang.ref包中的weak,soft和phantom引用开始。看看那些,尤其是构建缓存(已经有java.util.WeakHashMap)。现在深入了解ReferenceQueue,您将开始拥有更多控制权。最后抓住垃圾收集器本身的文档,你将能够控制它运行的频率,不同收集区域的大小以及所使用的算法类型(对于Java 5,请参阅http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html)。

答案 74 :(得分:7)

您可以使用String.format()构建字符串sprintf样式。

String w = "world";
String s = String.format("Hello %s %d", w, 3);

您当然也可以使用特殊说明符来修改输出。

更多信息:http://java.sun.com/j2se/1.5.0/docs/api/java/util/Formatter.html#syntax

答案 75 :(得分:6)

围绕finally声明的一些控制流技巧return

int getCount() { 
  try { return 1; }
  finally { System.out.println("Bye!"); }
}

definite assignment的规则将检查始终通过简单的控制流分析分配最终变量:

final int foo;
if(...)
  foo = 1;
else
  throw new Exception();
foo+1;

答案 76 :(得分:6)

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

答案 77 :(得分:6)

没有读过这个

Integer a = 1;
Integer b = 1;
Integer c = new Integer(1);
Integer d = new Integer(1);

Integer e = 128;
Integer f = 128;

assertTrue (a == b);   // again: this is true!
assertFalse(e == f); // again: this is false!
assertFalse(c == d);   // again: this is false!

通过搜索java的整数池(内部'缓存'从-128到127进行自动装箱)或者查看Integer.valueOf来了解更多信息

答案 78 :(得分:6)

源代码网址。例如。这是一些合法的java源代码:

http://google.com

(是的,它出现在Java Puzzlers中。我笑了......)

答案 79 :(得分:6)

同一个类的实例可以访问其他实例的私有成员:

class Thing {
  private int x;

  public int addThings(Thing t2) {
    return this.x + t2.x;  // Can access t2's private value!
  }
}

答案 80 :(得分:5)

已经mentioned可以使用最终数组从匿名内部类中传递变量。

另一种可以说是更好,更不丑的方法是使用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();
            }
        }
    }
});

在这个特定的例子中,我们可以简单地等待消息使其变为非空,但是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 ,或者在特定代码段中有意义的东西。

答案 81 :(得分:5)

阅读约书亚布洛赫的“Java Puzzlers”,你会受到启发和恐惧。

答案 82 :(得分:5)

交集类型允许您(有点排序)执行具有继承层次结构的枚举。您不能继承实现,但可以将其委托给辅助类。

enum Foo1 implements Bar {}
enum Foo2 implements Bar {}

class HelperClass {
   static <T extends Enum<T> & Bar> void fooBar(T the enum) {}
}

当您有许多实现某种模式的不同枚举时,这很有用。例如,有许多具有父子关系的枚举对。

enum PrimaryColor {Red, Green, Blue;}
enum PastelColor {Pink, HotPink, Rockmelon, SkyBlue, BabyBlue;}

enum TransportMedium {Land, Sea, Air;}
enum Vehicle {Car, Truck, BigBoat, LittleBoat, JetFighter, HotAirBaloon;}

您可以编写通用方法,说“好的,给定一个枚举值,该值是某些其他枚举值的父级,子类型的所有可能子枚举中有多少百分比将此特定父值作为其父级?”,以及拥有所有类型安全和没有铸造完成。 (例如:“Sea”占所有可能车辆的33%,而“Green”占所有可能车辆的20%)。

代码看起来像这样。它非常讨厌,但有办法让它变得更好。特别要注意的是“leaf”类本身非常简洁 - 泛型类的声明非常难看,但你只能将它们写成onece。一旦通用类存在,那么使用它们很容易。

import java.util.EnumSet;

import javax.swing.JComponent;

public class zz extends JComponent {

    public static void main(String[] args) {
        System.out.println(PrimaryColor.Green + " " + ParentUtil.pctOf(PrimaryColor.Green) + "%");
        System.out.println(TransportMedium.Air + " " + ParentUtil.pctOf(TransportMedium.Air) + "%");
    }


}

class ParentUtil {
    private ParentUtil(){}
    static <P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> //
    float pctOf(P parent) {
        return (float) parent.getChildren().size() / //
                (float) EnumSet.allOf(parent.getChildClass()).size() //
                * 100f;
    }
    public static <P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> //
    EnumSet<C> loadChildrenOf(P p) {
        EnumSet<C> cc = EnumSet.noneOf(p.getChildClass());
        for(C c: EnumSet.allOf(p.getChildClass())) {
            if(c.getParent() == p) {
                cc.add(c);
            }
        }
        return cc;
    }
}

interface Parent<P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> {
    Class<C> getChildClass();

    EnumSet<C> getChildren();
}

interface Child<P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> {
    Class<P> getParentClass();

    P getParent();
}

enum PrimaryColor implements Parent<PrimaryColor, PastelColor> {
    Red, Green, Blue;

    private EnumSet<PastelColor>    children;

    public Class<PastelColor> getChildClass() {
        return PastelColor.class;
    }

    public EnumSet<PastelColor> getChildren() {
        if(children == null) children=ParentUtil.loadChildrenOf(this);
        return children;
    }
}

enum PastelColor implements Child<PrimaryColor, PastelColor> {
    Pink(PrimaryColor.Red), HotPink(PrimaryColor.Red), //
    Rockmelon(PrimaryColor.Green), //
    SkyBlue(PrimaryColor.Blue), BabyBlue(PrimaryColor.Blue);

    final PrimaryColor  parent;

    private PastelColor(PrimaryColor parent) {
        this.parent = parent;
    }

    public Class<PrimaryColor> getParentClass() {
        return PrimaryColor.class;
    }

    public PrimaryColor getParent() {
        return parent;
    }
}

enum TransportMedium implements Parent<TransportMedium, Vehicle> {
    Land, Sea, Air;

    private EnumSet<Vehicle>    children;

    public Class<Vehicle> getChildClass() {
        return Vehicle.class;
    }

    public EnumSet<Vehicle> getChildren() {
        if(children == null) children=ParentUtil.loadChildrenOf(this);
        return children;
    }
}

enum Vehicle implements Child<TransportMedium, Vehicle> {
    Car(TransportMedium.Land), Truck(TransportMedium.Land), //
    BigBoat(TransportMedium.Sea), LittleBoat(TransportMedium.Sea), //
    JetFighter(TransportMedium.Air), HotAirBaloon(TransportMedium.Air);

    private final TransportMedium   parent;

    private Vehicle(TransportMedium parent) {
        this.parent = parent;
    }

    public Class<TransportMedium> getParentClass() {
        return TransportMedium.class;
    }

    public TransportMedium getParent() {
        return parent;
    }
}

答案 83 :(得分:5)

逗号&amp;阵列。这是合法的语法:String s [] = {
 “123”,
 “234”
};

答案 84 :(得分:5)

字符串参数化类工厂。

Class.forName( className ).newInstance();

从部署jar文件加载资源(属性文件,xml,xslt,image等)。

this.getClass().getClassLoader().getResourceAsStream( ... ) ;

答案 85 :(得分:5)

答案 86 :(得分:5)

Java 1.6 Update 10及更高版本中的下一代Java插件具有一些非常简洁的功能:

  • 传递java_arguments参数以将参数传递给创建的JVM。这允许您控制给予applet的内存量。
  • 为每个小程序创建单独的类加载器或甚至单独的JVM。
  • 指定要使用的JVM版本。
  • 在您只需要完整Java库功能的子集的情况下安装部分Java内核。
  • 更好的Vista支持。
  • 支持(实验性)将小程序拖出浏览器并在导航时继续运行。

此处记录了许多其他内容:http://jdk6.dev.java.net/plugin2/

此版本的更多内容:http://jdk6.dev.java.net/6u10ea.html

答案 87 :(得分:5)

Java 6(来自Sun)附带一个嵌入式JavaScript解释器。

http://java.sun.com/javase/6/docs/technotes/guides/scripting/programmer_guide/index.html#jsengine

答案 88 :(得分:4)

SwingWorker,用于轻松管理来自后台线程的用户界面回调。

答案 89 :(得分:4)

Functors非常酷。它们非常接近函数指针,在Java中通常很快就会说这是不可能的。

Functors in Java

答案 90 :(得分:4)

您可以使用Class<T>对象添加泛型类型的运行时检查,当在某个配置文件中创建类并且无法为泛型类型添加编译时检查时,这会派上用场班上的。你不希望这个类在运行时爆炸,如果应用程序配置错误而且你不希望所有你的类都充斥着支票实例。

public interface SomeInterface {
  void doSomething(Object o);
}
public abstract class RuntimeCheckingTemplate<T> {
  private Class<T> clazz;
  protected RuntimeChecking(Class<T> clazz) {
    this.clazz = clazz;
  }

  public void doSomething(Object o) {
    if (clazz.isInstance(o)) {
      doSomethingWithGeneric(clazz.cast(o));
    } else {
      // log it, do something by default, throw an exception, etc.
    }
  }

  protected abstract void doSomethingWithGeneric(T t);
}

public class ClassThatWorksWithStrings extends RuntimeCheckingTemplate<String> {
  public ClassThatWorksWithStrings() {
     super(String.class);
  }

  protected abstract void doSomethingWithGeneric(T t) {
    // Do something with the generic and know that a runtime exception won't occur 
    // because of a wrong type
  }
}

答案 91 :(得分:4)

您可以在枚举类的方法定义中切换(this)。让我大喊“哇!”当我发现这确实有用时,就大声说道。

答案 92 :(得分:4)

显然,对于某些调试版本,有一个选项可以从HotSpot转储本机(JIT)汇编代码:http://weblogs.java.net/blog/kohsuke/archive/2008/03/deep_dive_into.html

不幸的是,我无法通过该帖子中的链接找到该版本,如果有人能找到更精确的网址,我很乐意使用它。

答案 93 :(得分:3)

由于还没有人说过(我想)我最喜欢的功能是自动拳击!

public class Example
{
    public static void main(String[] Args)
    {
         int a = 5;
         Integer b = a; // Box!
         System.out.println("A : " + a);
         System.out.println("B : " + b);
    }
}

答案 94 :(得分:3)

几年前,当我不得不做Java(1.4.x)时,我想要一个eval()方法,并且用Java编写的Suns javac(是?)所以它只是链接tools.jar并使用一些胶水 - 围绕它编码。

答案 95 :(得分:2)

您可以覆盖一个方法并让超类构造函数调用它(这可能会让C ++程序员感到意外。)

Example

答案 96 :(得分:1)

我很喜欢

  1. javadoc的taglet和doclet,使我们能够自定义javadoc输出。
  2. JDK tools:jstat,jstack等。

答案 97 :(得分:0)

Java Bean属性访问器方法必须以“get”和“set”开头。

即使Josh Bloch在Effective Java中也出错了。

答案 98 :(得分:-3)

当我第一次发现Ternary-Operator等于一个简单的if-then-else语句时,我感到很惊讶:

minVal = (a < b) ? a : b;

答案 99 :(得分:-8)

让我感到惊讶的是,接口可以扩展多个接口,但类只能扩展一个类。