Tag Archives: java puzzle

Java Puzzle (4) shutdown hook

Puzzle 39
public class HelloGoodbye{
try{
System.out.println(“Hello World”);
System.exit(0);
} finally {
System.out.println(“Goodbye World”);
}
}
上面这段代码会打印出什么呢? 要知道答案则需要了解System.exit(0)这个方法在执行过程中到底发生了哪些事情。System.exit方法会导致当前运行线程停止并使其它所以线程都终止,因此finally这代码不会被执行。
System.exit被调用后,在虚拟机在退出前会执行两个清除任务。第一,它会执行所以通过Runtime.addShutdownHook注册的shutdown hooks.它能有效的释放JVM之外的资源。第二个清除任务是运行相关的finalizer方法。
如果需要在调用System.exit方法后仍然打印出”Goodbye World”,可采用如下的方法:
System.out.println(“Hello World”);
Runtime.getRuntime().addShutdownHook(
new Thread(){
public void run(){
System.out.println(“Goodbye world”);
}
}
)
System.exit(0);
前段时间在看Yurii在和篇文章中提到shutdown hook,当时不知道这是干什么的,也没深究,通过这个Puzzle终于明白了。其实shutdown hook可以做许多的事情,在JVM使用到外部资源时都可以保证JVM在退出时正确的释放了这些资源。最极端的变量数据库连接了,以前通过sql plus连上Oralce后,sqlplus不正常退出后,Oracle上面那个链接并不会关闭。不知道使用Java的数据库线程池在JVM崩溃时会不会有这问题。总之如Yurii所说:在编写Java服务程序的时候,记得设置退出的钩子函数(RunTime.getRunTime.addShutdownHook)是一个非常好的习惯。

Puzzle 39

public class HelloGoodbye{

try{

System.out.println(“Hello World”);

System.exit(0);

} finally {

System.out.println(“Goodbye World”);

}

}

上面这段代码会打印出什么呢? 要知道答案则需要了解System.exit(0)这个方法在执行过程中到底发生了哪些事情。System.exit方法会导致当前运行线程停止并使其它所以线程都终止,因此finally这代码不会被执行。

System.exit被调用后,在虚拟机在退出前会执行两个清除任务。第一,它会执行所以通过Runtime.addShutdownHook注册的shutdown hooks.它能有效的释放JVM之外的资源。第二个清除任务是运行相关的finalizer方法终结对象。

如果需要在调用System.exit方法后仍然打印出”Goodbye World”,可采用如下的方法:

System.out.println(“Hello World”);

Runtime.getRuntime().addShutdownHook(

new Thread(){

public void run(){

System.out.println(“Goodbye world”);

}

}

)

System.exit(0);

前段时间在看Yurii这篇文章中提到shutdown hook,当时不知道这是干什么的,也没深究,通过这个Puzzle终于明白了。其实shutdown hook可以做许多的事情,在JVM使用到外部资源时,可以保证JVM在退出时正确的释放了这些资源。比较典型的应用是数据库连接,文件锁等。以前试过通过sql plus连上Oralce,然后sqlplus不正常退出,Oracle服务上面对应的那个链接并不会关闭。不知道使用Java的数据库线程池在JVM崩溃时会不会有这问题。总之如Yurii所说:在编写Java服务程序的时候,记得设置退出的钩子函数(RunTime.getRunTime.addShutdownHook)是一个非常好的习惯。

在了解shutdown hook时找到这篇文章:Use JVM Shutdown Hooks to Optimize Resources,展示如何使用它。在Tomcat的源代码中也有用到shutdownHook。在Catalina.java这个类中的start和stop方法有使用到shutdownHook。

Java Puzzle (3)

Puzzle 20
package com.javapuzzlers
public class Me{
public static void main(String[] args){
System.out.println(Me.class.getName().replaceAll(“.”,”/”) + “.class”);
}
}
这段代码会打印什么?  结果是很令人意外的/////////////.class。原因是String的replaceAll方法中两个参数是当作正则表达式来处理,在正则表达式中”.”可以匹配任意字符,因此所有的文字都会被替换成”/”。当看到书中这样解释时,确实有点无语,因为replace方法是把参数当作字符来处理的,这两个方法在风格上的不一致,让使用者头疼。快跑提到的解决办法有两种如下:
System.out.println(Me.class.getName().replaceAll(“\\.”,”/”) + “.class”);
System.out.println(Me.class.getName().replaceAll(Pattern.quote(“.”),”/”) + “.class”);
第一种是对字符进行转义,程序不再将其作为正则表达式中的特殊字符。第二种方法使用Pattern.quote处理字符,其原理与前一种一致,只不过程序员不需要显式去转义。
Puzzle 21
System.out.println(Me.class.getName().replaceAll(“\\.”,File.separator) + “.class”);
上面这行打印语句会打印出什么呢? 谜底让人很有趣。上面这段代码在Unix like系统下能正常运行,在Windows下则会出错。 前面讲到,String.replaceAll方法中,对两个参数都是作为一段正则表达式来处理,在Windows下,File.separator对应的是”\”,这是个专门用于转义的特殊字符,不能单独作为替换变量,因此程序出错。书中提供了如下的解决方法:
System.out.println(Me.class.getName().replaceAll(“\\.”,Matcher.quoteReplacement(File.separator)) + “.class”);
或者使用String.replace方法替代replaceAll方法。
其它的Puzzle中还提到了String的charset的问题,这个问题以前碰到有,因此在看书时没有被迷惑。看过这几个Puzzle后,发现有目的去看看相应的Java API实现代码应该能学到不少东西。以前只是草草的看了一下API代码,收获并不大。

Puzzle 20

package com.javapuzzlers

public class Me{

public static void main(String[] args){

System.out.println(Me.class.getName().replaceAll(“.”,”/”) + “.class”);

}

}

这段代码会打印什么?  结果是很令人意外的/////////////.class。原因是String的replaceAll方法中两个参数是当作正则表达式来处理,在正则表达式中”.”可以匹配任意字符,因此所有的文字都会被替换成”/”。当看到书中这样解释时,确实有点无语,因为replace方法是把参数当作字符来处理的,这两个方法在风格上的不一致,让使用者头疼。快跑提到的解决办法有两种如下:

System.out.println(Me.class.getName().replaceAll(“\\.”,”/”) + “.class”);

System.out.println(Me.class.getName().replaceAll(Pattern.quote(“.”),”/”) + “.class”);

第一种是对字符进行转义,程序不再将其作为正则表达式中的特殊字符。第二种方法使用Pattern.quote处理字符,其原理与前一种一致,只不过程序员不需要显式去转义。

Puzzle 21

System.out.println(Me.class.getName().replaceAll(“\\.”,File.separator) + “.class”);

上面这行打印语句会打印出什么呢? 谜底让人很有趣。上面这段代码在Unix like系统下能正常运行,在Windows下则会出错。 前面讲到,String.replaceAll方法中,对两个参数都是作为一段正则表达式来处理,在Windows下,File.separator对应的是”\”,这是个专门用于转义的特殊字符,不能单独作为替换变量,因此程序出错。书中提供了如下的解决方法:

System.out.println(Me.class.getName().replaceAll(“\\.”,Matcher.quoteReplacement(File.separator)) + “.class”);

或者使用String.replace方法替代replaceAll方法。

在其它的Puzzle中还提到了String的charset的问题,这个问题以前碰到过,因此在看书时没有被迷惑。看过这几个Puzzle后,发现带着一定的目的去看看相应的Java API实现代码应该能学到不少东西。以前草草浏览API源代码的过程中,这些细节完全被忽略了。

Java Puzzle (2)

Java Puzzle笔记 [Day2]
Puzzle 8
char x = ‘X’;
int i = 0;
System.out.println(true ? x : 0);
System.out.println(false ? i : x);
上面这段代码打印出来的是什么? 运行程序后会发现打印出来的并不是XX,而是X88。原因是a?b:c这个操作符在执行时,有如下规则:
1.如果b,c类型一致,则采用该类型
2.如果b或c是byte,char,short,同时另外一个数是常量,并且类型是int,运行结果仍然是原来的类型。
3.否则会对运算的结果进行向上转型,转型成两者较高的那个类型。
在上面的例子中,第一个打印语句x后面的是0,因此结果是char类型,而第二个打印语句i是一个变量,类型是int,整个语句的结果转型成int,所以打印出的是X的值 88.
Puzzle 9
short x = 0 ;
int i = 123456 ;
x += i ;
x = x + i ;
这个Puzzle出错的点在于+= -= *= /=等这些组合赋值操作符的奇特作用。这些组合赋值操作符在执行过程中,如果赋的值Overflow时,并不会提示出错。
而下面这个句子则会在编译时提示出错。
看了一些其它的Puzzle,发现很多都是稀奇古怪的用法引起的错误。这些用法在平时工作中不太会用到,其实写代码时,尽量用最能用的方法来写,避免那些只有少数人才
了解的Tricks。奇怪的是,有些人却喜欢用这些Tricks来展示自己知道这些东西。 代码最重要的就是简单易懂,现在性能上的要求不是那么严格的条件下,为了性能写一些
很难懂的代码是不可取的。

这两天又看了一些Puzzles,发现其中有些并不值得写出来,因为平时开发过程中几乎从来没有看到有人用过。因此挑里面两个常用的,而我又不明白做一下笔记。看的过程发现有必要认真读一遍Java Language Specification了。

Puzzle 8

char x = ‘X’;

int i = 0;

System.out.println(true ? x : 0);

System.out.println(false ? i : x);

上面这段代码打印出来的是什么? 运行程序后会发现打印出来的并不是XX,而是X88。原因是a?b:c这个操作符在执行时,有如下规则:

1.如果b,c类型一致,则采用该类型

2.如果b或c是byte,char,short,同时另外一个数是常量,并且类型是int,运行结果仍然是原来的类型。

3.否则会对运算的结果进行向上转型,转型成两者较高的那个类型。

在上面的例子中,第一个打印语句x后面的是0,因此结果是char类型,而第二个打印语句i是一个变量,类型是int,整个语句的结果转型成int,所以打印出的是X的值 88.

Puzzle 9

short x = 0 ;

int i = 123456 ;

x += i ;

x = x + i ;

这个Puzzle出错的点在于+= -= *= /=等这些组合赋值操作符的奇特作用。这些组合赋值操作符在执行过程中,如果赋的值Overflow时,并不会提示出错。而下面这个句子则会在编译时提示出错。

看了一些其它的Puzzle,发现很多都是稀奇古怪的用法引起的错误。这些用法在平时工作中不太会用到,其实写代码时,尽量用最能用的方法来写,避免那些只有少数人才

了解的Tricks。奇怪的是,有些人却喜欢用这些Tricks来展示自己知道这些东西。 代码最重要的就是简单易懂,现在性能上的要求不是那么严格的条件下,为了所谓性能写一些很难懂的代码是不可取的。

Java Puzzle (1)

Java Puzzles
昨天开始看Java Puzzle这本书,这是一本讲述Java及JDK中让人迷惑的地方的一本书。书中所讲的东西确实很让人迷惑,我在看的过程中不断冒冷汗。
为了加深记忆,每天做一次笔记,记录其中的Puzzles。
Puzzle 1
public static boolean isOdd(int i){
return i % 2 == 1;
}
这个Puzzle的关键在于,%操作符在对负数操作时返回的不是 1,而是 -1。 Java中对于%的定义是:(a/b)*b +(a%b) = a
因此正确的判断奇数的方法应该是:i%2 != 0 。
Puzzle 2
System.out.println(2.00-1.10)
这条语句打印出来的是什么?
这个Puzzle的是Double.toString()方法不一定会产生准确的精度,所有的浮点数在计数时都会存在偏差,应该尽量使用BigDecimal来进行运算。
Puzzle 3
final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000;
final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000 ;
System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);
上面这段代码会打印出什么?
看到这个Puzzle的答案时,我直冒冷汗,暗自祈祷以前写过的代码没出现这样的问题。上面这段代码会导致Overflow,这个Overflow是在计算MICROS_PER_DAY时产生的。
虽然MICROS_PER_DAY声明是long型,但是计算(24 * 60 * 60 * 1000 * 1000)这个表达式时,仍然是以int型运算,并不会转型为long再计算,因此导致Overflow。
因此保险的写法是:
final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000;
final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000 ;
这个Puzzle严重违背了Unix的补救原则:出现异常时,马上退出并给出足够错误信息。
看过这几个Puzzle之后,让我对这本书产生了非常浓厚的兴趣。Java API和JDK原来存在着如此多不为人知的秘密,让人捉摸不定。
从一个语言及平台来讲,存在着这种需要使用者时时注意的陷阱是非常不友好的。这些所谓的“奇技淫巧”对于使用者来说是一种恶梦。
在Java Puzzle这本书中,作者也提到了当初在设计API及JDK时,应该改进的方法,可惜的是,这些暂时是无法实现了。

昨天开始看Java Puzzle这本书,这是一本讲述Java及JDK中让人迷惑的地方的一本书。书中所讲的东西确实很让人迷惑,我在看的过程中不断冒冷汗。

为了加深记忆,每天做一次笔记,记录其中的Puzzles及自己在看书过程中的一些想法。

Puzzle 1

public static boolean isOdd(int i){

return i % 2 == 1;

}

这个Puzzle的关键在于,%操作符在对负数操作时返回的不是 1,而是 -1。 Java中对于%的定义是:(a/b)*b +(a%b) = a

因此正确的判断奇数的方法应该是:i%2 != 0 。

Puzzle 2

System.out.println(2.00-1.10)

这条语句打印出来的是什么?这个Puzzle的是Double.toString()方法不一定会产生准确的精度,所有的浮点数在计数时都会存在偏差,应该尽量使用BigDecimal来进行运算。

Puzzle 3

final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000;

final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000 ;

System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);

上面这段代码会打印出什么?

看到这个Puzzle的答案时,我直冒冷汗,暗自祈祷以前写过的代码没出现这样的问题。上面这段代码会导致Overflow,这个Overflow是在计算MICROS_PER_DAY时产生的。虽然MICROS_PER_DAY声明是long型,但是计算(24 * 60 * 60 * 1000 * 1000)这个表达式时,仍然是以int型运算,并不会转型为long再计算,因此导致Overflow。

因此保险的写法是:

final long MICROS_PER_DAY = 24L * 60 * 60 * 1000 * 1000;

final long MILLIS_PER_DAY = 24 L* 60 * 60 * 1000 ;

这样子在计算过程中就会装所以的数字转换成long型,避免了Overflow的错误。其实这个Puzzle严重违背了Unix的补救原则:出现异常时,马上退出并给出足够错误信息。

看过这几个Puzzle之后,让我对这本书产生了非常浓厚的兴趣。Java API和JDK原来存在着如此多不为人知的秘密,让人捉摸不定。从一个语言及平台来讲,存在着这种需要使用者时时注意的陷阱是非常不友好的。这些所谓的“奇技淫巧”对于使用者来说是一种恶梦。在Java Puzzle这本书中,作者也提到了当初在设计API及JDK时,应该改进的方法,可惜的是,这些暂时是无法实现了。