Java的隐藏功能

gro*_*rom 295 java

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

Bor*_*zic 432

几个月前,当我第一次发现它时,双支撑初始化让我感到意外,从未听说过它.

ThreadLocals通常不是众所周知的存储每线程状态的方法.

由于JDK 1.5 Java具有非常好的实现和强大的并发工具,而不仅仅是锁,它们存在于java.util.concurrent中,一个特别有趣的例子是java.util.concurrent.atomic子包,它包含实现比较的线程安全原语和交换操作,可以映射到这些操作的实际本机硬件支持版本.

  • "双支撑初始化"是一个非常委婉的名称,用于创建一个匿名的内部类,掩盖真实发生的事情并使其听起来好像内部类本打算以这种方式使用.这是一种我宁愿隐藏的模式. (51认同)
  • 请注意,如果您保留对使用此"双括号"惯用法初始化的集合的引用(或者如果我们通过其真实名称调用它 - 带有初始化程序块的匿名类),则隐式保存对外部对象的引用,这可能会导致令人讨厌的内存泄漏.我建议完全避免它. (49认同)
  • 双括号初始化......很奇怪......我会过于广泛地采用那个特定的习惯用法,因为它实际上会创建一个对象的匿名子类,这可能会导致令人困惑的equals/hashcode问题.java.util.concurrent是一个非常棒的包. (40认同)
  • 几乎,它不是一个真正的静态块,而是一个"初始化块",它是不同的,因为它在不同的时间执行(请参阅我在答案中提供的链接以获取更多详细信息) (11认同)
  • 我教过*Java,这是我第一次遇到这种语法......这表明你永远不会停止学习= 8-) (6认同)
  • 为了确保我理解,双括号创建一个匿名内部类,然后在其中创建一个静态块,然后允许您从静态上下文执行方法.正确? (4认同)

Apo*_*isp 279

类型参数方差中的联合联合:

public class Baz<T extends Foo & Bar> {}
Run Code Online (Sandbox Code Playgroud)

例如,如果您想要一个兼容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);
}
Run Code Online (Sandbox Code Playgroud)

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

  • @Grasper:不,在这种情况下不提供OR(不相交联合).但您可以使用不相交的union数据类型,例如Either <A,B>.此类型是Pair <A,B>类型的双重类型.查看Functional Java库或Scala核心库以获取此类数据类型的示例. (9认同)
  • 是否有可能在那里有一个"OR"而不是&? (5认同)
  • 你应该说你必须只扩展一个类和几个接口 - >公共类Baz <T扩展Clazz&Interface1和InterfaceI ...而不是类Baz <T扩展Clazz1和ClazzI> (5认同)

Dav*_*son 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");
  }
}
Run Code Online (Sandbox Code Playgroud)

执行该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
Run Code Online (Sandbox Code Playgroud)

我想如果你有多个构造函数并需要公共代码,这些将是有用的

它们还为初始化类提供语法糖:

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

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

  • 此外,与init()方法不同,它可以初始化最终字段. (40认同)
  • 这个优于需要调用的显式方法的优点是,如果有人稍后添加构造函数,则不需要记住调用init(); 这将自动完成.这可以防止未来程序员的错误. (38认同)
  • 人们经常不认证(例如http://stackoverflow.com/questions/281100/281127#281127),特别质疑他们的技术优势.但如果这里有更多的程序员研究他们的SCJP,那么这不会被许多人视为"隐藏的特征".;-) (12认同)
  • 我敢打赌,即使是"24小时内的java"书也有这个"明显的特征".阅读更多人:)( (12认同)
  • 如果你扩展课程并实例化各种孩子怎么办?它仍然会以同样的方式行事吗? (2认同)

Kev*_*ong 201

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


cro*_*wne 173

自Java 6以来的Classpath外卡.

java -classpath ./lib/* so.Main
Run Code Online (Sandbox Code Playgroud)

代替

java -classpath ./lib/log4j.jar:./lib/commons-codec.jar:./lib/commons-httpclient.jar:./lib/commons-collections.jar:./lib/myApp.jar so.Main
Run Code Online (Sandbox Code Playgroud)

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


Geo*_*uba 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;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 对于许多程序员来说尤其不为人知的(也可能也是如此),你可以实际标记并打破任何旧程序块.它不必是一个循环 - 你可以只定义一些任意的块,给它一个标签,并使用break. (75认同)
  • 在某些情况下,在嵌套循环结构中,继续下一个外循环迭代会很有用.这将合理地使用此功能. (31认同)
  • 它根本不是goto,它只能返回到先前的迭代(即:你不能向前跳).这与迭代返回false时发生的机制相同.说java有goto就像说任何编译器生成JUMP指令的语言都有goto语句. (27认同)
  • 因此,您基于Java琐事进行访谈,而不是基于能力来解决问题和思考设计.我会确保我从不采访过你的公司.:) (4认同)
  • 它可以是任何块 (3认同)
  • 好吧,我宁愿选择以多种方式做到这一点.例如,我看到有人使用System.exit(1); 在Servlet和EJB代码中,但这并不意味着我们应该删除System.exit(); 来自JDK,对吧? (2认同)
  • 我认为我唯一一次使用这个结构就是在非常紧迫的截止日期将汇编代码转换为java. (2认同)
  • 所以,你通过伸展一个观点和/或进行一些远近的概括和/或假设来评论.我会确保永远不要再读你的评论了.:) (2认同)

ser*_*g10 144

从JDK 1.5开始,协变返回类型如何?它的宣传非常糟糕,因为它是一个不容易添加的东西,但据我所知,泛型工作绝对是必要的.

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

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

class ThreadSafeSortedSub extends Souper {
    @Override
    ConcurrentSkipListSet<String> values() {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以调用子类的values方法并获取s 的已排序线程安全Set,而无需向下转换为.StringConcurrentSkipListSet

  • 我经常使用它.clone()就是一个很好的例子.它应该返回Object,这意味着你必须说例如(List)list.clone().但是,如果您声明为List clone(){...},那么转换是不必要的. (24认同)

Jam*_*fer 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;
    }
  }
Run Code Online (Sandbox Code Playgroud)

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

  • 这似乎更像是一个"陷阱",而不是一个隐藏的功能,虽然有一些方法可以用作一个,使用这种方法不是一个好主意. (21认同)
  • 这是令人讨厌的,但它也只是最终运作的逻辑结果.try/catch/finally流控制执行它的目的,但仅限于某些限制.同样,你必须小心不要在catch/finally块中引起异常,否则你也会抛弃原始异常.如果在try块中执行System.exit(),则不会调用finally块.如果打破正常流量,就会打破正常流量...... (7认同)

小智 141

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

代替:

if( null != aObject && aObject instanceof String )
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

只需使用:

if( aObject instanceof String )
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

  • 遗憾的是,这是一个鲜为人知的特征.我见过很多类似于第一块代码的代码. (9认同)
  • 那是因为Java有一个你看不到的特殊(隐藏)null类型,也没有引用. (4认同)

Adr*_*uat 134

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

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

  private int mAge;
  Cats(int age) {
    mAge = age;
  }
  public int getAge() {
    return mAge;
   }
}
Run Code Online (Sandbox Code Playgroud)

您甚至可以拥有一个"常量特定类主体",它允许特定的枚举值覆盖方法.

这里有更多文档.

  • 实际上非常棒的功能 - 使枚举OO并以非常干净的方式解决了许多初始化问题. (20认同)
  • @Georgy:请参阅Joshua Bloch的Effective Java(第2版)中的第3项; "虽然这种方法尚未被广泛采用,但单元素枚举类型是实现单例的最佳方式." (20认同)
  • Georgy:Singleton是对象的一个​​实例,而不是具有一个值的对象. (6认同)
  • Enum作为单身人士?只有一个值的枚举? (5认同)
  • 轻微的挑剔:`mAge`应该是最终的.在枚举中很少出现非最终字谜的原因. (3认同)

Kev*_*ong 121

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

Collections.<String,Integer>emptyMap()
Run Code Online (Sandbox Code Playgroud)

  • 而上帝是丑陋和混乱.与类型安全无关. (10认同)
  • 我喜欢这个.它使你的代码更加明确,对于那些将在一两年内维持它的可怜的草皮来说更加清晰. (8认同)
  • 在您声明了静态泛型方法(例如`public static <T> T foo(T t)`)的情况下,这实际上非常有用.然后,您可以调用`Class.<Type> foo(t);` (6认同)

Pet*_*rey 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; }
}
Run Code Online (Sandbox Code Playgroud)

编辑:多年后....

我在这里使用这个功能

public enum AffinityStrategies implements AffinityStrategy {
Run Code Online (Sandbox Code Playgroud)

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

通过使用界面,开发人员可以定义自己的策略.使用一种enum方法,我可以定义一个内置的集合(五个).

  • 这太疯狂了.(1) (27认同)
  • @Arian这不是疯狂.这个.IS.JAVAAAAAAHHHH! (12认同)

Pau*_*cks 104

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

public void foo(String... bars) {
   for (String bar: bars)
      System.out.println(bar);
}
Run Code Online (Sandbox Code Playgroud)

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

  • 关于这个的重要一点是在调用方法时,你可以写:foo("first","second","third") (23认同)
  • 所以旧的你好世界可以改写; public static void main(String ... args){System.out.println("Hello World!"); } (9认同)

Chr*_*ola 93

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

windows:CTRL- Break在你的java cmd/console窗口中

UNIX: kill -3 PID

  • 在Unix中也是ctrl- \.或者使用JDK中的jstack. (15认同)
  • 谢谢,你刚刚教我,我的键盘有一个'Break`键. (9认同)
  • 或者使用jvisualvm. (2认同)
  • 在Windows上,只有在当前控制台窗口中运行进程时,CTRL-BREAK才有效.您可以使用JAVA_HOME/bin/jstack.exe.只需提供Windows进程ID即可. (2认同)

Jac*_*eow 89

有几个人发布了关于实例初始化器的信息,这里有一个很好的用途:

Map map = new HashMap() {{
    put("a key", "a value");
    put("another key", "another value");
}};
Run Code Online (Sandbox Code Playgroud)

如果您只是快速而简单地执行某些操作,那么这是一种快速初始化地图的方法.

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

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 );
Run Code Online (Sandbox Code Playgroud)

当然可以滥用:

    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");
                        }
                     });
                 }});
        }});
    }};
Run Code Online (Sandbox Code Playgroud)

  • 虽然看了它之后,我不得不说我对这提供的自然筑巢感到奇怪,甚至是"滥用"版本. (17认同)
  • 但是,使用它有一个副作用.创建匿名对象,这可能永远不会很好. (15认同)
  • 是的 - 我非常喜欢"滥用"版本,我认为它非常清晰可读,但也许只是我. (4认同)
  • 绝对同意,反映gui层次结构的代码层次结构是对一系列方法调用的巨大改进. (3认同)

jod*_*ell 88

动态代理(在1.3中添加)允许您在运行时定义符合接口的新类型.它的出现次数惊人.

  • 动态代理是选择编写Foo接口并在任何地方使用它的一个很好的理由,使用默认的"FooImpl"类.起初看起来可能很难看("为什么不只是有一个名为Foo的类?")但是单元测试的未来灵活性和模拟能力的好处是很方便的.虽然有很多方法可以用于非接口,但它们通常需要额外的东西,比如cblib. (10认同)

All*_*nde 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;
}
Run Code Online (Sandbox Code Playgroud)

  • 是的,但更强烈:"最终变量的值必须设置一次" (29认同)
  • +1同意,这是在编译时发现错误的另一个有价值的工具,也是程序员由于某种原因似乎不愿意使用的工具.请注意,因为从Java 5开始,'final'也具有线程安全含义,能够在构造函数中设置最终变量是非常宝贵的. (6认同)
  • 虽然对于这个特定的方法,我只是使用多个返回.事实上,在大多数适用的情况下,我可能会将它重构为一个单独的方法并使用多个返回. (4认同)

Mo.*_*Mo. 62

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

如果你设计一种新语言(比如在scala-case中),你可以立即使用所有现有的库,因此从一开始你的语言就是"有用的".

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

  • Java 7将有新的字节码来支持动态语言. (29认同)
  • 不,它实际上不是一个非常好的VM.它仅用于运行JAVA.无类型动态和函数语言不能很好地使用它.如果您想使用VM,则应使用.NET/Mono.这是为了与每种语言一起工作...... (18认同)
  • 实际上,JVM仅用于运行Java字节码.您可以将大多数现代语言编译为Java字节码.关于Java Bytecode缺少的唯一内容是动态语言支持,指针和尾递归支持. (14认同)
  • JVM不支持泛型,而.NET VM则支持泛型.JVM远不是最好的. (13认同)
  • @ Hades32:实际上.NET VM与JVM非常相似.它最近才得到动态语言的支持(使用DLR),Java 7也即将获得支持..NET的经典"每种语言"(C#,Visual Basic.NET,...)都具有完全相同的功能集. (12认同)
  • 不要忽视对JVM没有直接支持的特定语言功能的抱怨......但我倾向于认为稳定性,跨平台一致性和良好性能远远超出了JVM获得额外分数的原因.我已经在许多平台(包括AS/400)上使用服务器端Java多年,并且几乎完全忘记了它 - 错误几乎总是在我可以修复的代码中,并且它根本不会崩溃. (3认同)

Ron*_*Ron 58

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

new Object() {
  void foo(String s) {
    System.out.println(s);
  }
}.foo("Hello");
Run Code Online (Sandbox Code Playgroud)

  • new Thread(){public void run(){...}} .start(); (20认同)
  • @Wouter - 在这种情况下,在匿名对象(`start()`)上调用的方法实际上并没有在子类中定义... (10认同)

Bru*_*ine 56

asList的方法java.util.Arrays允许可变参数,泛型方法和自动装箱的一个很好的组合:

List<Integer> ints = Arrays.asList(1,2,3);
Run Code Online (Sandbox Code Playgroud)

  • 你想用List构造函数包装返回的列表,否则int将是固定大小(因为它由数组支持) (15认同)
  • `Arrays.asList`有一个不寻常的特性,你可以`set()`元素但不是`add()`或`remove()`.所以我通常将它包装在`new ArrayList(...)`或`Collections.unmodifiableList(...)`中,这取决于我是否希望列表可修改. (2认同)

Tah*_*tar 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;
}
}
Run Code Online (Sandbox Code Playgroud)

  • 引用封闭类仍然很有用,例如.如果你需要把它传递给某个方法或者construtor. (7认同)
  • 只有在您隐藏了名称(在您的情况下,使用方法参数名称)时才需要这样做.如果您将参数调用为其他参数,那么您可以直接访问Container类的sortAscending成员变量而不使用'this'. (4认同)

Phi*_*Lho 52

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

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

    System.exit(0);
  }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 整洁,带有评论的标签:) (15认同)
  • 这个是在<a rel="nofollow noreferrer" href="http://www.javapuzzlers.com/"> Java Puzzlers </a>中. (4认同)

Das*_*Das 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);
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

  • 这是一个太阳.*API本身并不是Java语言的一部分 (20认同)

Dev*_*ler 42

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

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


Dol*_*lph 40

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

(解释)


小智 38

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

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

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

它读取比通常的someValue*1000或someValue/1000好很多.


Mar*_*ade 37

语言级断言关键字.

  • assert的问题在于它需要在运行时打开. (19认同)
  • 但如果它被禁用,就好像它不在那里.您可以在代码中添加任意数量的断言,如果它们被禁用,您将不会受到任何性能损失. (10认同)
  • 我相信这是关于断言的好事:它可以在不受惩罚的情况下关闭. (5认同)

Bin*_*mas 37

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


18R*_*bit 36

在1.5中添加for-each循环结构.我<3.

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

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

for (Suit suit : suits)
  for (Rank rank : ranks)
    sortedDeck.add(new Card(suit, rank));
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

链接到Sun文档

  • 我认为在这里使用`i`是非常混乱的,因为大多数人都希望我是一个索引而不是数组元素. (30认同)
  • 唯一让我感到困惑的是,看起来创建一个用于访问循环计数值的关键字真的很容易,但你不能.如果我想循环遍历两个数组,并根据第一个中的值更改第二个,我被迫使用旧语法,因为我没有第二个数组的偏移量. (28认同)
  • 令人遗憾的是它不能与枚举一起使用,就像JNDI中使用的那样.它回到那里的迭代器. (6认同)
  • @extraneon:看看Collections.list(Enumeration <T> e).这应该有助于在foreach循环中迭代枚举. (3认同)

Rah*_*thy 34

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

  • Void比Object更具体,因为Void只能为null,Object可以是任何东西. (4认同)
  • 不完全的.在某些时候,你需要具体:Executors.newSingleThreadExecutor().submit(new Callable <Void>(){..}) - 你无法实例化一个新的Callable <?>(),你需要指定显式类型 - 因此,它是Callable <Object>的替代品. (2认同)

Pet*_*rey 30

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

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

您可以;

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

顺便说一句:错误地使用这个类会杀死JVM.我不知道哪个JVM支持这个类,所以它不可移植.

  • 这不是Java的隐藏功能,而是某些特定JVM实现的隐藏功能. (7认同)
  • 我最近用它来分配一个16 GB的块(你用Java做不到的东西)只需要30秒来填充.我真的可以看到主内存是新磁盘.;) (4认同)

Lui*_*ano 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!"));
    }
}
Run Code Online (Sandbox Code Playgroud)

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

public static void main(String[] args) {
     throw null;
}
Run Code Online (Sandbox Code Playgroud)

猜猜这是什么印刷品:

Long value = new Long(0);
System.out.println(value.equals(0));
Run Code Online (Sandbox Code Playgroud)

而且,猜猜这回归:

public int returnSomething() {
    try {
        throw new RuntimeException("foo!");
    } finally {
        return 0;
    }
}
Run Code Online (Sandbox Code Playgroud)

以上不应该让优秀的开发者感到惊讶


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

String[] strings = new String[] { "foo", "bar" };
// the above is equivalent to the following:
String[] strings = { "foo", "bar" };
Run Code Online (Sandbox Code Playgroud)

所以遵循Java代码是完全有效的:

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

    public void example() {
        String[] strings = { "foo", "bar" };
        doSomething(strings);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

public class Foo {

    public void doSomething(String[] arg) {}

    public void example() {
        doSomething({ "foo", "bar" });
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 有效的原因是编译器无法推断出数组的类型.但好的清单. (2认同)

SRG*_*SRG 28

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

此外,它很容易设置.

            Runtime.getRuntime().addShutdownHook(new Thread() {
                  public void run() {
                      endApp();
                  }
            });;
Run Code Online (Sandbox Code Playgroud)

  • 如果使用javaw启动应用程序并启动Windows注销,则不会在Windows中调用关闭挂钩.必须有一个控制台窗口.叹.我试图用这个来标记我在我们网站上的"不在办公室",最后不得不忍受最小化的控制台窗口. (3认同)

Jac*_*eow 27

的价值:

new URL("http://www.yahoo.com").equals(new URL("http://209.191.93.52"))
Run Code Online (Sandbox Code Playgroud)

true.

(来自Java Puzzlers)

  • 仅当您连接到Internet时.如果它无法解析地址,它将返回false,因此URL类会破坏equals()合约.更好地使用java.net中的URI类. (48认同)

Kev*_*Day 26

如果你做了很多JavaBean开发并使用属性更改支持,你通常会编写很多像这样的setter:

public void setFoo(Foo aFoo){
  Foo old = this.foo;
  this.foo = aFoo;
  changeSupport.firePropertyChange("foo", old, aFoo);
}
Run Code Online (Sandbox Code Playgroud)

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

public void setFoo(Foo aFoo){
  changeSupport.firePropertyChange("foo", this.foo, this.foo = aFoo);
}
Run Code Online (Sandbox Code Playgroud)

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

  • 是 - 定义或执行参数的定义非常明确.我不确定我是否同意这比在每个JavaBean中的每个setter中都有3行垃圾代码更令人困惑 - 更好的方法是将注意力集中在你想要编写的代码而不是这种类型的样板上! (7认同)
  • 您可以使用项目lombok. (5认同)

Mic*_*ale 25

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

List<String> ls = List("a", "b", "c");
Run Code Online (Sandbox Code Playgroud)

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

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")));
Run Code Online (Sandbox Code Playgroud)

  • 这不是语言的一部分; 链接中的作者定义了用于创建列表的"List"方法 (19认同)
  • static import java.util.Arrays; List <String> names = asList("jim","john") (6认同)
  • 这是一个方法,如:... public static <T> List <T> List(T ... elems){return Arrays.asList(elems); 您还可以编写:List <String> myList = new ArrayList <String>(Arrays.asList("One","Two","Three")); //正如另一篇文章所述 (2认同)

PPS*_*PPS 23

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

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

Java 5中的JConsole:Java 5中的 JConsole

Java 6中的JConsole:Java 6中的 JConsole

在阅读本文时,请仔细阅读本系列中的其他工具: Java 6故障排除工具

  • 当然,JConsole将被取代或相当精致,我认为已经从6u7.但是许多人仍然使用旧版本的太阳JVM,因此需要JConsole.我还没有找到任何支持JVisualVM将支持旧版本JDK的理论的东西. (2认同)

Osc*_*Ryz 23

不是那么隐蔽,而是有趣.

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

最初由RusselW发布在Strangest 语言功能上

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

$ java WithoutMain
Look ma, no main!!
Run Code Online (Sandbox Code Playgroud)

  • 这是一个简单的滥用静态初始化,没有什么我会考虑任何类型的功能...... (8认同)
  • 添加一个`System.exit(0);`来抑制那个丑陋的异常...... (3认同)

Bil*_*l K 22

如果不使用默认初始值设定项,Java处理会对变量定义进行巧妙处理.

{
   int x;

   if(whatever)
      x=1;

   if(x == 1)
      ...
}

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

int x=0;
String s=null;

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

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

  • 尽可能使用final进行额外检查. (5认同)
  • +1同意 - 出于某种原因,有些人发现"混乱"不提供变量的初始值,好像他们认为编译器秘密地选择随机数或其他东西.但正如你正确地说,它是在编译时发现某些错误的有用工具. (3认同)

Jas*_*ang 21

这不是一个真正隐藏的功能,但当我看到这个编译好的时候它确实给了我一个大惊喜:

public int aMethod(){
    http://www.google.com
    return 1;
}
Run Code Online (Sandbox Code Playgroud)

它编译的原因是http://www.google.com的"http:"部分被编译器视为标签,其余部分是注释.

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

  • 这是一个重复的答案 (13认同)
  • ...并且每个方法最多只能使用一个http地址,因为标签必须是唯一的. (7认同)

oxb*_*kes 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);

}
Run Code Online (Sandbox Code Playgroud)

  • 它们被称为本地类:) http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#247766 (5认同)
  • 匿名类被高估了.尝试调试一个,或在现场支持一个,你会明白我的意思.一旦你在发布版本中丢失了行号,就很难跟踪它们. (4认同)

And*_*rew 19

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

系统托盘


Mo.*_*Mo. 17

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


you*_*uri 16

我喜欢静态导入方法.

例如,创建以下util类:

package package.name;

public class util {

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

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

}
Run Code Online (Sandbox Code Playgroud)

然后像这样使用它.

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()
     }

}
Run Code Online (Sandbox Code Playgroud)

Static Imports适用于任何类,甚至是Math ...

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");
    }
}
Run Code Online (Sandbox Code Playgroud)


chi*_*tom 16

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

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

列出subList(int fromIndex,int toIndex)

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

       list.subList(from, to).clear();
Run Code Online (Sandbox Code Playgroud)

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

  • 小心subList,即使你只存储对子列表的引用,它也会将整个底层列表保存在内存中.它与功能语言中的"尾部"操作非常不同. (3认同)

Jon*_*cke 16

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

jmap -histo:直播PID

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


kca*_*k11 16

用于显示基于Java控制台的应用程序的初始屏幕的功能.

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

例如:

java -splash:C:\myfolder\myimage.png -classpath myjarfile.jar com.my.package.MyClass
Run Code Online (Sandbox Code Playgroud)

C:\myfolder\myimage.png每当执行"com.my.package.MyClass"类时,内容将显示在屏幕的中央


ser*_*g10 15

这不是一个特色,但它让我轻笑,这goto是一个保留的词,除了提示javac戳你的眼睛之外什么也不做.只是为了提醒你,你现在在OO-land.

  • 面向对象编程与不使用"goto"之间是否存在某种关系? (10认同)
  • http://stackoverflow.com/questions/15496/hidden-features-of-java#answer-39433 :-) (4认同)

小智 15

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

  • 当你将鼠标悬停在一个方法上时,它会在Eclipse中弹出它的美感...... (12认同)

小智 15

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

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

  • 你甚至可以用泛型来做这件事.Google Collections有很好的实用工具. (4认同)

Rom*_*Guy 14

strictfp关键字.(我从来没有看到它用于真正的应用程序:)

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

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

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

  • 我自己用过strictfp.这是针对一个程序,其中寄存器(80位)和RAM(64位)之间的_double_s可能会导致问题 (2认同)

Osc*_*Ryz 14

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

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

(new Object() {
    public String someMethod(){ 
        return "some value";
    }
}).someMethod();
Run Code Online (Sandbox Code Playgroud)

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


yal*_*tar 13

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


st0*_*0le 13

C风格的printf():)

System.out.printf("%d %f %.4f", 3,Math.E,Math.E);
Run Code Online (Sandbox Code Playgroud)

产量:3 2.718282 2.7183

二进制搜索(和它的返回值)

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

与C#类似,如果在数组中找不到"2",则返回负值,但是如果您获取返回值的1的补码,则实际上可以获得可以插入"2"的位置.

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

我觉得它很漂亮...... :)


Joh*_*her 12

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


Mat*_*ngs 12

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


小智 12

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

能够写:

String s = "A";
s += " String"; // so s == "A String"
Run Code Online (Sandbox Code Playgroud)

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

String s = new String("A");
s = new StringBuffer(s).append(" String").toString();
Run Code Online (Sandbox Code Playgroud)

为一个简单的连接提供了一个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!
Run Code Online (Sandbox Code Playgroud)

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

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();
Run Code Online (Sandbox Code Playgroud)

并且比原始循环运行速度快大约80 +%!(我运行的一些基准测试高达180%)

  • 文字"A"`实际上是一个java.lang.String,尽管它的后备字符数组以不同的方式分配给动态创建的字符串. (2认同)

dme*_*ter 11

最终的例如变量:

对多线程代码非常有用,它可以更容易地争论实例状态和正确性.在行业环境中没有看到太多,并且在java类中经常没有想到.


static {something;}:

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


Pet*_*ore 11

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

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

  • 您还可以在变量名中使用£和€.以及任何UNICODE字母æ,ø,å等. (7认同)

Mic*_*ers 10

"const"是关键字,但您无法使用它.

int const = 1;   // "not a statement"
const int i = 1; // "illegal start of expression"
Run Code Online (Sandbox Code Playgroud)

我想编译器编写者认为它可能会在未来使用,他们最好保留它.


Dav*_*vis 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 )
      ;
  }
}
Run Code Online (Sandbox Code Playgroud)

$ time java Slow
real 0m15.397s
$ time java
slow real 0m20.012s
$ time java
slow real 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;
  }
}
Run Code Online (Sandbox Code Playgroud)

$ time java Fast
real 0m12.003s
$ time java fast
real 0m9.840s
$ time java fast
real 0m9.686s

平均值:10.509秒

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

这种技术的另一个优点(总是使用访问器)是它消除了Slow类中的潜在错误.如果第二个线程不断地将i的值重置为0(slow.setI( 0 )例如,通过调用),则Slow类永远不会结束其循环.调用访问器并使用局部变量消除了这种可能性.

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

  • "过早优化"是用于描述程序员让性能考虑因素影响一段代码设计的情况的短语.这可能导致设计不像以前那样干净或代码不正确,因为优化会使代码变得复杂,并且程序员会因优化而分散注意力.[参考:http://en.wikipedia.org/wiki/Optimization_%28computer_science%29] (2认同)

Las*_*ico 10

使用StringBuilder而不是StringBuffer在不需要同步管理时使用StringBuilder.它将提高您的应用程序的性能.

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

不要在instanciation使用那些无限<>语法:

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

// Can now be replaced with this:

Map<String, List<String>> anagrams = new HashMap<>();
Run Code Online (Sandbox Code Playgroud)
  • 交换机中的字符串: 链接

在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;
}
Run Code Online (Sandbox Code Playgroud)

这个旧代码:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在可以用这个更简单的代码替换:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 你的意思是`StringBuilder`而不是`StringWriter`?`StringBuffer`和`StringBuilder`的API是相同的,但使用`StringWriter`需要一些代码更改. (4认同)
  • 他实际上是指StringBuilder,它不是线程安全的,但速度更快.StringBuffer是线程安全的,但速度较慢.只有在构建字符串缓冲区时需要线程安全时才应使用. (2认同)

Ala*_*ore 9

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

String realProp = new String(prop.getBytes("ISO-8859-1"), "UTF-8");
Run Code Online (Sandbox Code Playgroud)

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


Osc*_*Ryz 9

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

虽然这些方法是私密的!! ,它们在对象序列化期间由JVM " 神秘地 "调用.

private void writeObject(ObjectOutputStream out) throws IOException;
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 如果您没有阅读文档,那就太令人惊讶了. (7认同)

sta*_*ker 9

标识符可以包含像变音符号这样的外语字符:

而不是写:

String title="";
Run Code Online (Sandbox Code Playgroud)

有人可以写:

String Überschrift="";
Run Code Online (Sandbox Code Playgroud)

  • 在我看来,风格不好.你知道我的意思,如果你不得不使用一些你不理解的语言的注释和标识符代码.代码不应本地化. (8认同)

小智 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();
Run Code Online (Sandbox Code Playgroud)

  • 在我看来,这不是一个隐藏的功能.扫描仪是一个库. (4认同)

小智 8

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


Hux*_*uxi 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+"]";
    }
}
Run Code Online (Sandbox Code Playgroud)

执行这个程序......

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

...将产生以下输出:

Foo[bar=17]
Foo[bar=42]
Foo[bar=23]
Run Code Online (Sandbox Code Playgroud)


小智 8

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

int[] arr = {1, 2, 3};
int[] arr2 = arr.clone();
Run Code Online (Sandbox Code Playgroud)

  • @Finbarr:恰恰相反.它做了一个浅层克隆; 内部对象只是获得对它们的另一个引用.深度克隆的"最简单"方法是序列化和反序列化,或者实际了解您正在复制的内容. (8认同)

Bil*_*ell 7

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


小智 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).


Han*_*örr 7

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

    final String foo = "42";
    new Thread() {
        public void run() {
             dowhatever(foo);
        }
    }.start();
Run Code Online (Sandbox Code Playgroud)

有点像关闭,不是吗?

  • 它*是一个封闭! (3认同)

Sar*_*tha 7

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

String w = "world";
String s = String.format("Hello %s %d", w, 3);
Run Code Online (Sandbox Code Playgroud)

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

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

  • 那是怎么隐藏的? (2认同)

Jon*_*cke 7

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

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

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

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

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


war*_*sze 6

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


Bru*_*ine 6

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

int getCount() { 
  try { return 1; }
  finally { System.out.println("Bye!"); }
}
Run Code Online (Sandbox Code Playgroud)

明确赋值的规则将检查始终通过简单的控制流分析分配最终变量:

final int foo;
if(...)
  foo = 1;
else
  throw new Exception();
foo+1;
Run Code Online (Sandbox Code Playgroud)


Dav*_*lle 6

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

class Thing {
  private int x;

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

  • 但是,如果你无法访问它的内部,你将如何做一个正确的哈希/等于实现? (6认同)
  • 太可怕了.不要这样做.这不是因为我是人类,另一个人有权调查我的肠子;-) (3认同)

Dav*_*ton 6

源代码网址.例如,这里有一些合法的java源代码:

http://google.com
Run Code Online (Sandbox Code Playgroud)

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

  • 重复的答案 (2认同)

Kar*_*ell 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!
Run Code Online (Sandbox Code Playgroud)

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

  • 确切的限制是依赖于实现的(只有一些最小大小),因此在某些VM中,第二个测试也可能是真的. (3认同)

Mar*_*mer 5

字符串参数化类工厂.

Class.forName( className ).newInstance();
Run Code Online (Sandbox Code Playgroud)

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

this.getClass().getClassLoader().getResourceAsStream( ... ) ;
Run Code Online (Sandbox Code Playgroud)


Sar*_*tha 5

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

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

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

更多来自此版本:http://jdk6.dev.java.net/6u10ea.html


pau*_*ray 5

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

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

class HelperClass {
   static <T extends Enum<T> & Bar> void fooBar(T the enum) {}
}
Run Code Online (Sandbox Code Playgroud)

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

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;}
Run Code Online (Sandbox Code Playgroud)

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

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

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;
    }
}
Run Code Online (Sandbox Code Playgroud)


Dav*_*ton 5

阅读约书亚布洛赫的"Java Puzzlers",你会既开明又恐惧.


Iva*_*sov 5

已经提到过,可以使用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();
            }
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

在这个特定的例子中,我们可以简单地等待消息使其变为非空,但是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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这里我假设在接收到消息时,另一个线程调用messageHandler(如果它不为null)handleMessage(…)方法.messageHandler不能只是MessageHandler类型:这样你就会对变化的变量进行同步,这显然是一个bug.

当然,它不需要是InterruptedException,它可能类似于IOException,或者在特定代码段中有意义的东西.


sib*_*ick 5

逗号和数组.它是合法的语法:String s [] = {
"123",
"234" ,
};