diff --git a/README.md b/README.md index 053f033..624fcdb 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,33 @@ + stackoverflow-Java-top-qa ======================= 对stackoverflow上Java相关、投票数TOP100的问答进行翻译,欢迎点star,我们会持续更新!!! 为了让"翻译"更有意义,给阅读者带来更多、更有效的收获,我们会有一些加工: 例如,对问题进行分类,整合多个答案、删除冗余内容、加上自己的验证结果、心得等等 - + 对于参与翻译的人,这也是很好的一个学习、理解过程,欢迎大家一起来翻译 ------------- ### 如何参与翻译(欢迎加入翻译组QQ群485011036) -如何参与: -- 请从下文"待翻译问题链接"中寻找你感兴趣的问答进行翻译。翻译好的问答,放到contents目录下,无需更新readme.md文档。之后提一个PR,我会对你的翻译做一个审校,并更新到readme中。 +####如何参与: +- 请从下文"待翻译问题链接"中寻找你感兴趣的问答进行翻译。翻译好的问答,放到contents目录下,无需更新readme.md文档。之后提一个PR,我负责合并PR并更新到readme中。 - 另外,为了避免多人重复新翻译一个问题,你可以提issue,说明你计划翻译的问题及时间点,我可以先更新到下面的"未翻译问题"中,说明已有人领了这个问题。当然,也不一定要提issue,一般情况下,只要及时提pr,我及时审核,出现"撞车"的概率并不高。 -一些基本的约定: +####一些基本的约定: - 文档的文件名,和stackoverflowhich-notnull-java-annotation-should-i-usew上的url保持一致。例如,http://stackoverflow.com/questions/8710619/java-operator 的文件名, 就是java-operator.md - 在每篇翻译文档内容的最后,要附上stackoverflow的原文链接 -每个人可以做(但不限于): +####每个人可以做(但不限于): - 找未翻译的问题进行翻译 - 优化已翻译的问题 - 输出问答精简汇总版(把所有的问答集中到一个md文件,然后尽量精简,让别人可以在一天内把这100个问题的精髓都看完) - 输出gitbook版本(现在直接在github上查看,体验不好) +####文档优化反馈: +请大家多多反馈,优化已翻译好的文章:可以到[吐槽区](https://github.com/giantray/stackoverflow-java-top-qa/issues/66)吐槽,也可以在已翻译文章基础上进行优化,提新的PR。文章质量的提升,需要大家一起努力! + + ### 目录 > 基础语法 @@ -53,6 +58,18 @@ stackoverflow-Java-top-qa * [比较java枚举成员使用equal还是==](https://github.com/giantray/stackoverflow-java-top-qa/blob/master/contents/comparing-java-enum-members-or-equals.md) * [用java怎么创建一个文件并向该文件写文本内容](https://github.com/giantray/stackoverflow-java-top-qa/blob/master/contents/how-to-create-a-file-and-write-to-a-file-in-java.md) * [serialVersionUID 有什么作用?该如何使用?](https://github.com/giantray/stackoverflow-java-top-qa/blob/master/contents/what-is-a-serialversionuid-and-why-should-i-use-it.md) +* [为什么Java的```Vector```类被认为是过时的或者废弃的](https://github.com/giantray/stackoverflow-java-top-qa/blob/master/contents/why-is-java-vector-class-considered-obsolete-or-deprecated.md) +* [Java的foreach循环是如何工作的](https://github.com/giantray/stackoverflow-java-top-qa/blob/master/contents/how-does-the-java-for-each-loop-work.md) +* [为什么相减这两个时间(1927年)会得到奇怪的结果](/contents/why-is-subtracting-these-two-times-in-1927-giving-a-strange-result.md) +* [Java 中如何将 String 转换为 enum](/contents/lookup-enum-by-string-value.md) +* [该什么时候使用 ThreadLocal变量,它是如何工作的](/contents/when-and-how-should-i-use-a-threadlocal-variable.md) +* [servlets的运行原理](/contents/how-do-servlets-work-instantiation-shared-variables-and-multithreading.md) +* [如何计算MD5值](/contents/how-can-i-generate-an-md5-hash.md) +* [Java中软引用和弱引用的区别](/contents/what-is-the-difference-between-a-soft-reference-and-a-weak-reference-in-java.md) +* [JSF, Servlet 和 JSP (三种技术)有什么区别](/contents/what-is-the-difference-between-jsf-servlet-and-jsp.md) +* [Java内部类和嵌套静态类](/contents/java-inner-class-and-static-nested-class.md) +* [@Component, @Repository, @Service的区别](/contents/whats-the-difference-between-component-repository-service-annotations-in.md) +* [如何创建泛型java数组](/contents/how-to-create-a-generic-array-in-java.md) > 编程技巧 @@ -72,7 +89,12 @@ stackoverflow-Java-top-qa * [我应该用哪一个@NotNull注解](https://github.com/giantray/stackoverflow-java-top-qa/blob/master/contents/which-notnull-java-annotation-should-i-use.md) * [怎样将堆栈追踪信息转换为字符串](https://github.com/giantray/stackoverflow-java-top-qa/blob/master/contents/how-can-i-convert-a-stack-trace-to-a-string.md) * [如何处理 java.lang.outOfMemoryError PermGen space error](https://github.com/giantray/stackoverflow-java-top-qa/blob/master/contents/dealing-with-java-lang-outofmemoryerror-permgen-space-error.md) - +* [如何在整数左填充0](https://github.com/giantray/stackoverflow-java-top-qa/blob/master/contents/how-can-i-pad-an-integers-with-zeros-on-the-left.md) +* [在调用 instanceof 前需要进行null检查吗](https://github.com/giantray/stackoverflow-java-top-qa/blob/master/contents/is-null-check-needed-before-calling-instanceof.md) +* [如何从文件里读取字符串](/contents/how-do-i-create-a-java-string-from-the-contents-of-a-file.md) +* [遍历集合时移除元素,怎样避免ConcurrentModificationException异常抛出](/contents/iterating-through-a-collection-avoiding-concurrentmodificationexception-when-reiterating-through-a-collection-avoiding-concurrentmodificationexception-when-re.md) +* [如何让IntelliJ编辑器永久性显示代码行数](/contents/how-can-i-permanently-have-line-numbers-in-intellij.md) +* [如何使用maven把项目及其依赖打包为可运行jar包](/contents/how-can-i-create-an-executable-jar-with-dependencies-using-maven.md) > 网络 @@ -83,64 +105,46 @@ stackoverflow-Java-top-qa * [LinkedList、ArrayList各自的使用场景,如何确认应该用哪一个呢?](https://github.com/giantray/stackoverflow-java-top-qa/blob/master/contents/when-to-use-linkedlist-over-arraylist.md) * [StringBuilder和StringBuffer有哪些区别呢](https://github.com/giantray/stackoverflow-java-top-qa/blob/master/contents/stringbuilder-and-stringbuffer.md) * [为什么处理排序的数组要比非排序的快](https://github.com/giantray/stackoverflow-java-top-qa/blob/master/contents/why-is-processing-a-sorted-array-faster-than-an-unsorted-array.md) +* [如何使用Java创建一个内存泄漏的程序](https://github.com/giantray/stackoverflow-java-top-qa/blob/master/contents/creating-a-memory-leak-with-java.md) +* [为什么打印"B"会明显的比打印"#"慢](https://github.com/giantray/stackoverflow-java-top-qa/blob/master/contents/why-is-printing-b-dramatically-slower-than-printing.md) > 测试 * [如何测试 private 方法,变量或者内部类](https://github.com/giantray/stackoverflow-java-top-qa/blob/master/contents/how-to-test-a-class-that-has-private-methods-fields-or-inner-classes.md) +* [JUnit4如何断言确定异常的抛出](/contents/how-do-you-assert-that-a-certain-exception-is-thrown-in-junit-4-tests.md) > Android * [在Android里面下载文件,并在ProgressDialog显示进度](https://github.com/giantray/stackoverflow-java-top-qa/blob/master/contents/download-a-file-with-android-and-showing-the-progress-in-a-progressdialog.md) * [如何获取Android设备唯一ID](https://github.com/giantray/stackoverflow-java-top-qa/blob/master/contents/is-there-a-unique-android-device-id.md) +* [安装Android SDK的时候找不到JDK](contents/android-sdk-installation-doesnt-find-jdk.md) ### 待翻译问题链接(还剩x问题) -- [Why is subtracting these two times (in 1927) giving a strange result?](http://stackoverflow.com/questions/6841333/why-is-subtracting-these-two-times-in-1927-giving-a-strange-result) - [Proper use cases for Android UserManager.isUserAGoat()?](http://stackoverflow.com/questions/13375357/proper-use-cases-for-android-usermanager-isuseragoat) -- [Creating a memory leak with Java [closed]](http://stackoverflow.com/questions/6470651/creating-a-memory-leak-with-java) 用户AutumnLight正在翻译该问题 -- [Why is printing "B" dramatically slower than printing "#"?](http://stackoverflow.com/questions/21947452/why-is-printing-b-dramatically-slower-than-printing) -- [How can I create an executable jar with dependencies using Maven?](http://stackoverflow.com/questions/574594/how-can-i-create-an-executable-jar-with-dependencies-using-maven) - [Why is executing Java code in comments with certain Unicode characters allowed?](http://stackoverflow.com/questions/30727515/why-is-executing-java-code-in-comments-with-certain-unicode-characters-allowed) - [Convert a String to an enum in Java](http://stackoverflow.com/questions/604424/convert-a-string-to-an-enum-in-java) -- [Android SDK installation doesn't find JDK](http://stackoverflow.com/questions/4382178/android-sdk-installation-doesnt-find-jdk) -- [Java inner class and static nested class](http://stackoverflow.com/questions/70324/java-inner-class-and-static-nested-class) - ['Must Override a Superclass Method' Errors after importing a project into Eclipse](http://stackoverflow.com/questions/1678122/must-override-a-superclass-method-errors-after-importing-a-project-into-eclips) - [Fastest way to determine if an integer's square root is an integer](http://stackoverflow.com/questions/295579/fastest-way-to-determine-if-an-integers-square-root-is-an-integer) - [How to fix: Unsupported major.minor version 51.0 error?](http://stackoverflow.com/questions/10382929/how-to-fix-unsupported-major-minor-version-51-0-error) - [How to generate a random alpha-numeric string?](http://stackoverflow.com/questions/41107/how-to-generate-a-random-alpha-numeric-string) -- [Comparing Java enum members: == or equals()?](http://stackoverflow.com/questions/1750435/comparing-java-enum-members-or-equals) - [Failed to load the JNI shared Library (JDK)](http://stackoverflow.com/questions/7352493/failed-to-load-the-jni-shared-library-jdk) -- [How to create a Java String from the contents of a file?](http://stackoverflow.com/questions/326390/how-to-create-a-java-string-from-the-contents-of-a-file) -- [How do you assert that a certain exception is thrown in JUnit 4 tests?](http://stackoverflow.com/questions/156503/how-do-you-assert-that-a-certain-exception-is-thrown-in-junit-4-tests) - [What exactly is Apache Camel?](http://stackoverflow.com/questions/8845186/what-exactly-is-apache-camel) -- [How can I permanently have line numbers in IntelliJ?](http://stackoverflow.com/questions/13751/how-can-i-permanently-have-line-numbers-in-intellij) -- [How do servlets work? Instantiation, shared variables and multithreading](http://stackoverflow.com/questions/3106452/how-do-servlets-work-instantiation-shared-variables-and-multithreading) - [Access restriction on class due to restriction on required library rt.jar?](http://stackoverflow.com/questions/860187/access-restriction-on-class-due-to-restriction-on-required-library-rt-jar) - [How do I discover memory usage of my application in Android?](http://stackoverflow.com/questions/2298208/how-do-i-discover-memory-usage-of-my-application-in-android) -- [How can I generate an MD5 hash?](http://stackoverflow.com/questions/415953/how-can-i-generate-an-md5-hash) - [Uncatchable ChuckNorrisException](http://stackoverflow.com/questions/13883166/uncatchable-chucknorrisexception) - [Can I add jars to maven 2 build classpath without installing them?](http://stackoverflow.com/questions/364114/can-i-add-jars-to-maven-2-build-classpath-without-installing-them) - [Update Eclipse with Android development tools v. 23](http://stackoverflow.com/questions/24437564/update-eclipse-with-android-development-tools-v-23) - [Setting multiple jars in java classpath](http://stackoverflow.com/questions/219585/setting-multiple-jars-in-java-classpath) -- [Iterating through a list, avoiding ConcurrentModificationException when removing in loop](http://stackoverflow.com/questions/223918/iterating-through-a-list-avoiding-concurrentmodificationexception-when-removing) -- [Is null check needed before calling instanceof](http://stackoverflow.com/questions/2950319/is-null-check-needed-before-calling-instanceof) -- [How does the Java for each loop work?](http://stackoverflow.com/questions/85190/how-does-the-java-for-each-loop-work) - [What is the Java equivalent for LINQ?](http://stackoverflow.com/questions/1217228/what-is-the-java-equivalent-for-linq) - [Hibernate hbm2ddl.auto possible values and what they do?](http://stackoverflow.com/questions/438146/hibernate-hbm2ddl-auto-possible-values-and-what-they-do) -- [How to round a number to n decimal places in Java](http://stackoverflow.com/questions/153724/how-to-round-a-number-to-n-decimal-places-in-java) - [How can I pad an integers with zeros on the left?](http://stackoverflow.com/questions/473282/how-can-i-pad-an-integers-with-zeros-on-the-left) - [Sort ArrayList of custom Objects by property](http://stackoverflow.com/questions/2784514/sort-arraylist-of-custom-objects-by-property) -- [What's the difference between @Component, @Repository & @Service annotations in Spring?](http://stackoverflow.com/questions/6827752/whats-the-difference-between-component-repository-service-annotations-in) -- [Why is Java Vector class considered obsolete or deprecated?](http://stackoverflow.com/questions/1386275/why-is-java-vector-class-considered-obsolete-or-deprecated) - [Efficiency of Java "Double Brace Initialization"?](http://stackoverflow.com/questions/924285/efficiency-of-java-double-brace-initialization) - [Why does this go into an infinite loop?](http://stackoverflow.com/questions/3831341/why-does-this-go-into-an-infinite-loop) -- [When and how should I use a ThreadLocal variable?](http://stackoverflow.com/questions/817856/when-and-how-should-i-use-a-threadlocal-variable) - [decompiling DEX into Java sourcecode](http://stackoverflow.com/questions/1249973/decompiling-dex-into-java-sourcecode) -- [How to create a generic array in Java?](http://stackoverflow.com/questions/529085/how-to-create-a-generic-array-in-java) - [Why does Math.round(0.49999999999999994) return 1](http://stackoverflow.com/questions/9902968/why-does-math-round0-49999999999999994-return-1) - [Eclipse: Set maximum line length for auto formatting?](http://stackoverflow.com/questions/3697287/eclipse-set-maximum-line-length-for-auto-formatting) -- [What is the difference between a soft reference and a weak reference in Java?](http://stackoverflow.com/questions/299659/what-is-the-difference-between-a-soft-reference-and-a-weak-reference-in-java) - [What is the equivalent of the C++ Pair in Java?](http://stackoverflow.com/questions/156275/what-is-the-equivalent-of-the-c-pairl-r-in-java) -- [What is the difference between JSF, Servlet and JSP?](http://stackoverflow.com/questions/2095397/what-is-the-difference-between-jsf-servlet-and-jsp) - [How do I "decompile" Java class files?](http://stackoverflow.com/questions/272535/how-do-i-decompile-java-class-files) - [Useful Eclipse Java Code Templates [closed]](http://stackoverflow.com/questions/1028858/useful-eclipse-java-code-templates) - [How to call SOAP web service in Android](http://stackoverflow.com/questions/297586/how-to-call-soap-web-service-in-android) diff --git a/SUMMARY.md b/SUMMARY.md new file mode 100644 index 0000000..9f8edf2 --- /dev/null +++ b/SUMMARY.md @@ -0,0 +1 @@ +\# Summary* [前言](README.md) \ No newline at end of file diff --git a/contents/android-sdk-installation-doesnt-find-jdk.md b/contents/android-sdk-installation-doesnt-find-jdk.md new file mode 100644 index 0000000..117b823 --- /dev/null +++ b/contents/android-sdk-installation-doesnt-find-jdk.md @@ -0,0 +1,33 @@ +##安装Android SDK的时候找不到JDK + +###问题 +我在我的win7 64位的系统上安装Android SDK时,jdk-6u23-windows-x64.exe已经安装上了,但是Android SDK的安装程序却因为找不到已安装的JDK无法继续下去。 +这个问题出现过吗?有没有办法解决呢? + +![](http://ww2.sinaimg.cn/large/0060lm7Tgw1f72ny3m6oaj30ds0a0gmi.jpg) + +###回答1: +当你看到这个提示(找不到jdk)的时候按Back(返回),然后再点Next(下一步)。这个时候,它将会去寻找JDK + +###回答2: +实际安装: + + - 系统:windows 8.1 + - JDK文件: jdk-8u11-windows-x64.exe + - ADT文件:installer_r23.0.2-windows.exe +安装64位JDK,然后尝试第一个回答中的back-next的方法。然后尝试设置JAVA_HOME 根据错误信息的提示,但是,仍旧对我没有用处,然后,尝试如下解决办法: + +按照它说的做,设置JAVA_HOME在你的系统环境变量中,这个路径要使用正斜杠(/)而非反斜杠(\) + +**注意:** +当我把JAVA_HOME设置为C:\Program Files\Java\jdk1.6.0_31的时候还是不行,但是当我设置成C:/Program Files/Java/jdk1.6.0_31的时候就ok了。快把我逼疯了。 + +如果还不行,就把 %JAVA_HOME%加在环境变量Path的头部。 + +下面是我的环境变量的配置: + - JAVA_HOME=C:/Program Files/Java/jdk1.8.0_11 + - JRE_HOME=C:/Program Files/Java/jre8 + - Path=%JAVA_HOME%;C:... + +stackoverflow链接: +http://stackoverflow.com/questions/4382178/android-sdk-installation-doesnt-find-jdk \ No newline at end of file diff --git a/contents/avoiding-null-statements-in-java.md b/contents/avoiding-null-statements-in-java.md index baf0f60..aab0bc7 100644 --- a/contents/avoiding-null-statements-in-java.md +++ b/contents/avoiding-null-statements-in-java.md @@ -50,7 +50,8 @@ public interface Parser { 我们来改造一下 -类定义如下,这样定义findAction方法后,确保无论用户输入什么,都不会返回null对象 +类定义如下,这样定义findAction方法后,确保无论用户输入什么,都不会返回null对象: +```java public class MyParser implements Parser { private static Action DO_NOTHING = new Action() { public void doSomething() { /* do nothing */ } @@ -62,7 +63,7 @@ public class MyParser implements Parser { return DO_NOTHING; } }} - +``` 对比下面两份调用实例 1. 冗余: 每获取一个对象,就判一次空 @@ -74,7 +75,8 @@ if (parser == null) { } Action action = parser.findAction(someInput); if (action == null) { - // do nothing} else { + // do nothing} +else { action.doSomething();} ``` @@ -90,11 +92,11 @@ ParserFactory.getParser().findAction(someInput).doSomething(); - 如果要用equal方法,请用object<不可能为空>.equal(object<可能为空>)) 例如: 使用 -"bar".equals(foo) +`"bar".equals(foo) ` 而不是 -foo.equals("bar") +`foo.equals("bar") ` - Java8或者guava lib中,提供了Optional类,这是一个元素容器,通过它来封装对象,可以减少判空。不过代码量还是不少。不爽。 -- 如果你想返回null,请挺下来想一想,这个地方是否更应该抛出一个异常 +- 如果你想返回null,请停下来想一想,这个地方是否更应该抛出一个异常 stackoverflow链接: -http://stackoverflow.com/questions/271526/avoiding-null-statements-in-java?page=2&tab=votes#tab-top \ No newline at end of file +http://stackoverflow.com/questions/271526/avoiding-null-statements-in-java?page=2&tab=votes#tab-top diff --git a/contents/comparing-java-enum-members-or-equals.md b/contents/comparing-java-enum-members-or-equals.md index 287f68c..a83be17 100644 --- a/contents/comparing-java-enum-members-or-equals.md +++ b/contents/comparing-java-enum-members-or-equals.md @@ -44,10 +44,10 @@ public final boolean equals(Object other) { 答案是肯定的,因为枚举有着严格的实例化控制,所以你可以用 == 去做比较符,这个用法,在官方文档中也有明确的说明。 >JLS 8.9 Enums ->An enum type has no instances other than those defined by its enum constants. ->It is a compile-time error to attempt to explicitly instantiate an enum type. The final clone method in Enum>ensures that enum constants can never be cloned, and the special treatment by the serialization mechanism ensures>that duplicate instances are never created as a result of deserialization. Reflective instantiation of enum types>is prohibited. Together, these four things ensure that no instances of an enum type exist beyond those defined by>the enum constants. ->Because there is only one instance of each enum constant, it is permissible to use the == operator in place of the>equals method when comparing two object references if it is known that at least one of them refers to an enum ?>constant. (The equals method in Enum is a final method that merely invokes super.equals on its argument and ?>returns the result, thus performing an identity comparison.) +一个枚举类型除了定义的那些枚举常量外没有其他实例了。 +试图明确地说明一种枚举类型是会导致编译期异常。在枚举中final clone方法确保枚举常量从不会被克隆,而且序列化机制会确保从不会因为反序列化而创造复制的实例。枚举类型的反射实例化也是被禁止的。总之,以上内容确保了除了定义的枚举常量之外,没有枚举类型实例。 +因为每个枚举常量只有一个实例,所以如果在比较两个参考值,至少有一个涉及到枚举常量时,允许使用"=="代替equals()。(equals()方法在枚举类中是一个final方法,在参数和返回结果时,很少调用父类的equals()方法,因此是一种恒等的比较。) #### 什么时候 == 和 equals 不一样? As a reminder, it needs to be said that generally, == is NOT a viable alternative to equals. When it is, however (such as with enum), there are two important differences to consider: 通常来说 == 不是一个 equals的一个备选方案,无论如何有2个重要的不同处需要考虑: @@ -73,8 +73,8 @@ if (Color.BLACK == Chiral.LEFT); // DOESN'T COMPILE!!! Incompatible types! Bloch specifically mentions that immutable classes that have proper control over their instances can guarantee to their clients that == is usable. enum is specifically mentioned to exemplify. 具体来说,那些提供恰当实例控制的不可变类能够保证 == 是可用的,枚举刚好符合这个条件。 -> Item 1: Consider static factory methods instead of constructors -[...] it allows an immutable class to make the guarantee that no two equal instances exist: a.equals(b) if and only if a==b. If a class makes this guarantee, then its clients can use the == operator instead of the equals(Object) method, which may result in improved performance. Enum types provide this guarantee. +考虑静态工厂方法代替构造器 +它使得不可变的类可以确保不会存在两个相等的实例,即当且仅当a==b的时候才有a.equals(b)为true。如果类保证了这一点,它的客户端可以使用"=="操作符来代替equals(Object)方法,这样可以提升性能。枚举类型保证了这一点 总而言之,在枚举比较上使用 == , 因为: 1. 能正常工作 diff --git a/contents/how-can-i-create-an-executable-jar-with-dependencies-using-maven.md b/contents/how-can-i-create-an-executable-jar-with-dependencies-using-maven.md new file mode 100644 index 0000000..dab0dcf --- /dev/null +++ b/contents/how-can-i-create-an-executable-jar-with-dependencies-using-maven.md @@ -0,0 +1,99 @@ +## 如何使用maven把项目及其依赖打包为可运行jar包 + +#### 问题 + +我想把java项目打包为可运行的分布式jar包。我该怎样做,才能把项目中maven所依赖的jar包导入到我的项目jar包中? + +#### 回答 + +在`pom.xml`文件中,加入如下的插件: + +```xml + + + + maven-assembly-plugin + + + + + fully.qualified.MainClass + + + + jar-with-dependencies + + + + + +``` + +之后,运行maven命令: + +> mvn clean compile assembly:single + +`clean`,`compile`,`assembly:single`任务将会依次被执行;`compile`任务必须写在`assembly:single`之前,否则打包后的jar包内将不会有你的编译代码。 + +(译注:执行完后,会在你的maven项目的target目录下,生成想要的jar包,而不再需要使用`mvn package`命令进行打包) + +通常情况下,上述maven命令执行后会自动绑定到项目的构建阶段,从而保证了以后在执行`mvn install`命令时的jar包也会被构建。 +(译注:下面是实际上完整的默认的`pom.xml`配置,只不过``可以被省略,若省略则按照下述默认的配置执行) + +```xml + + maven-assembly-plugin + + + + fully.qualified.MainClass + + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + +``` + +#### 拓展 + +怎样去运行打包后的可运行jar包? + +* 对上述配置中已经指定了`main`函数所在类的jar包,打开命令行窗口,输入命令: + +```java +java -jar jar包的路径/jar包的名字.jar +``` + +例如: + +```Auto +java -jar D:\my_java_project\maven_test.jar +``` + +* 若在pom.xml并没有指定`main`方法所在类,那么该jar的运行应采取如下命令: + +```java +java -cp jar包的路径/jar包的名字.jar main方法所在类的全限定名 +``` + +例如: + +```java +java -cp D:\my_java_project\maven_test.jar com.my.path.MainClass +``` + + +#### StackOverflow地址 + +[http://stackoverflow.com/questions/574594/how-can-i-create-an-executable-jar-with-dependencies-using-maven](http://stackoverflow.com/questions/574594/how-can-i-create-an-executable-jar-with-dependencies-using-maven) \ No newline at end of file diff --git a/contents/how-can-i-generate-an-md5-hash.md b/contents/how-can-i-generate-an-md5-hash.md new file mode 100644 index 0000000..b122024 --- /dev/null +++ b/contents/how-can-i-generate-an-md5-hash.md @@ -0,0 +1,25 @@ +##如何计算MD5值 + +###问题 +Java中有没有方法可以计算一个String的MD5值? + + +###回答 +你可以用 ```MessageDigest``` 的MD5实例来计算String的MD5值。 + +使用 ```MessageDigest``` 和 String 时,一定要显式声明你的数据编码类型。如果你使用无参的 ```String.getBytes()``` , 它会以当前平台的默认编码来转换数据。不同平台的默认编码可能是不同的,这可能会导致你的数据不一致。 + +``` java +import java.security.*; + +.. + +byte[] bytesOfMessage = yourString.getBytes("UTF-8"); +MessageDigest md = MessageDigest.getInstance("MD5"); +byte[] thedigest = md.digest(bytesOfMessage); +``` + +如果你的要计算的数据量很大,你可以循环使用 ```.update(byte[])``` 方法来加载数据。加载完毕后用 ```.digest()``` 方法来得到计算出的MD5值。 + +stackoverflow链接 +http://stackoverflow.com/questions/415953/how-can-i-generate-an-md5-hash diff --git a/contents/how-can-i-pad-an-integers-with-zeros-on-the-left.md b/contents/how-can-i-pad-an-integers-with-zeros-on-the-left.md new file mode 100644 index 0000000..4c632df --- /dev/null +++ b/contents/how-can-i-pad-an-integers-with-zeros-on-the-left.md @@ -0,0 +1,123 @@ +## 如何在整数左填充0 + +### 问题 +如何在整数左填充0 +举例 1 = "0001" + + +### 答案一,String.format + + String.format("%05d", yournumber); + +用0填充,总长度为5 +https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html + +### 答案二,ApacheCommonsLanguage +如果需要在Java 1.5前使用,可以利用 Apache Commons Language 方法 + + org.apache.commons.lang.StringUtils.leftPad(String str, int size, '0') + +### 答案三,DecimalFormat + import java.text.DecimalFormat; + class TestingAndQualityAssuranceDepartment + { + public static void main(String [] args) + { + int x=1; + DecimalFormat df = new DecimalFormat("00"); + System.out.println(df.format(x)); + } + } + +### 答案四,自己实现 +如果效率很重要的话,相比于 String.format 函数的可以自己实现 + + /** + * @param in The integer value + * @param fill The number of digits to fill + * @return The given value left padded with the given number of digits + */ + public static String lPadZero(int in, int fill){ + + boolean negative = false; + int value, len = 0; + + if(in>= 0){ + value = in; + } else { + negative = true; + value = - in; + in = - in; + len ++; + } + + if(value == 0){ + len = 1; + } else{ + for(; value != 0; len ++){ + value /= 10; + } + } + + StringBuilder sb = new StringBuilder(); + + if(negative){ + sb.append('-'); + } + + for(int i = fill; i> len; i--){ + sb.append('0'); + } + + sb.append(in); + + return sb.toString(); + } + + 效率对比 + + public static void main(String[] args) { + Random rdm; + long start; + + // Using own function + rdm = new Random(0); + start = System.nanoTime(); + + for(int i = 10000000; i != 0; i--){ + lPadZero(rdm.nextInt(20000) - 10000, 4); + } + System.out.println("Own function: " + ((System.nanoTime() - start) / 1000000) + "ms"); + + // Using String.format + rdm = new Random(0); + start = System.nanoTime(); + + for(int i = 10000000; i != 0; i--){ + String.format("%04d", rdm.nextInt(20000) - 10000); + } + System.out.println("String.format: " + ((System.nanoTime() - start) / 1000000) + "ms"); + } + + 结果 + 自己的实现:1697ms + String.format:38134ms + +### 答案,Google Guava +Maven: + + + guava + com.google.guava + 14.0.1 + +样例: + + Strings.padStart("7", 3, '0') returns "007" + Strings.padStart("2020", 3, '0') returns "2020" +注意: +Guava 是非常有用的库,它提供了很多有用的功能,包括了Collections, Caches, Functional idioms, Concurrency, Strings, Primitives, Ranges, IO, Hashing, EventBus等 + + +stackoverflow原址: +http://stackoverflow.com/questions/473282/how-can-i-pad-an-integers-with-zeros-on-the-left \ No newline at end of file diff --git a/contents/how-can-i-permanently-have-line-numbers-in-intellij.md b/contents/how-can-i-permanently-have-line-numbers-in-intellij.md new file mode 100644 index 0000000..8f7e071 --- /dev/null +++ b/contents/how-can-i-permanently-have-line-numbers-in-intellij.md @@ -0,0 +1,29 @@ +## 如何让IntelliJ编辑器永久性显示代码行数 + +#### 问题 + +如何让IntelliJ编辑器永久性显示代码行数 + +#### 回答 + +##### IntelliJ 14.0之后的版本 + +打开软件的菜单`File`->`Settings`->`Editor`->`General`->`Appearance`,在右侧的配置`Show line numbers`打勾: +![image1][1] + +##### IntelliJ 8.1.2 - 13.X的版本 + +打开软件的菜单`File`->`Settings`->`Editor`->`Appearance`,在右侧的配置`Show line numbers`打勾: +![images2][2] + +#### 拓展 + +[IntelliJ IDEA 使用教程](http://www.phperz.com/article/15/0923/159068.html) + +#### StackOverflow地址 + +http://stackoverflow.com/questions/13751/how-can-i-permanently-have-line-numbers-in-intellij + + + [1]: http://i.stack.imgur.com/9DL9q.png + [2]: http://i.stack.imgur.com/JVZlJ.jpg \ No newline at end of file diff --git a/contents/how-do-i-create-a-java-string-from-the-contents-of-a-file.md b/contents/how-do-i-create-a-java-string-from-the-contents-of-a-file.md new file mode 100644 index 0000000..1dc835b --- /dev/null +++ b/contents/how-do-i-create-a-java-string-from-the-contents-of-a-file.md @@ -0,0 +1,55 @@ +##如何从文件里读取字符串 + +###从文件里读取所有文本: + +代码: +```java +static String readFile(String path, Charset encoding) + throws IOException +{ + byte[] encoded = Files.readAllBytes(Paths.get(path)); + return new String(encoded, encoding); +} + +``` + +###一行一行读入文本: + +Java 7 提供了一个方便的方法可以直接将文件中的文本一行一行读入,存放在一个List容器里。 +```JAVA +List lines = Files.readAllLines(Paths.get(path), encoding); +``` + +###内存使用率 + +第一个方法,一次读取所有文本的方法,占用内存较多,因为它一次性保留了文件的所有原始信息,包括换行符之类的"无用"字符。 + +第二个方法,按行读入,比起一次性全部读入,要消耗更少的内存。因为它每次只将一行的文件信息放在缓存中。然而,如果文本文件很大,这种方法依然会占用很多内存。 + +如果你的程序需要处理很大的文本文件,在设计的时候就要考虑,分配一块固定的缓存,每次从流中读入文件的一部分放入缓存,处理,然后清空缓存,把下一部分读入缓存,直到处理完所有的数据。 + +这里的"很大"是相对于计算机性能的。一般来说,几十个G的文件应当算是大文件。 + +###字符编码 + +还有一件事需要注意,就是字符编码。不同的平台有自己的默认编码,所以有时候你的程序需要指定编码,来保持平台无关/跨平台。 + +```StandardCharsets``` 类定义了常用的编码类型,你可以用如下方法调用: + +```java +String content = readFile("test.txt", StandardCharsets.UTF_8); +``` + +可以通过```Charset```类来获得平台默认的字符编码。 + +```java +String content = readFile("test.txt", Charset.defaultCharset()); +``` + +注: 这个答案与之前Java6版本时的答案完全不同。Java 7 新增的工具类极大的优化了字符处理,文件读取等功能。Java 6 常用的内存映射方法已不适合在Java 7 以后的版本使用。 + +### 原文链接 +http://stackoverflow.com/questions/326390/how-do-i-create-a-java-string-from-the-contents-of-a-file + + + diff --git a/contents/how-do-servlets-work-instantiation-shared-variables-and-multithreading.md b/contents/how-do-servlets-work-instantiation-shared-variables-and-multithreading.md new file mode 100644 index 0000000..148ab53 --- /dev/null +++ b/contents/how-do-servlets-work-instantiation-shared-variables-and-multithreading.md @@ -0,0 +1,52 @@ +##How do servlets work? Instantiation, shared variables and multithreading +###问题: +假设,我有一个web服务器可以支持无数的servlets,对于通过这些servlets的信息,我正在获取这些servlets的上下文环境,并设置session变量。 +现在,如果有两个或者更多的user用户发送请求到这个服务器,session变量会发生什么变化?session对于所有的user是公共的还是不同的user拥有不同的session。如果用户彼此之间的session是不同的,那么服务器怎么区分辨别不同的用户呢? +另外一些相似的问题,如果有N个用户访问一个具体的servlets,那么这个servlets是只在第一个用户第一次访问的时候实例化,还是为每一个用户各自实例化呢? +###答案: +####ServletContext +当servletcontainer(像tomcat)启动的时候,它会部署和加载所有的webapplications,当一个webapplication加载完成后,servletcontainer就会创建一个ServletContext,并且保存在服务器的内存中。这个webapp的web.xml会被解析,web.xml中的每个```, and ```或者通过注解```@WebServlet, @WebFilter and @WebListener```,都会被创建一次并且也保存在服务器的内存中。对于所有filter,```init()```方法会被直接触发,当servletcontainer关闭的时候,它会unload所有的webapplications,触发所有实例化的servlets和filters的```destroy()```方法,最后,servletcontext和所有的servlets,filter和listener实例都会被销毁。 + +####HttpServletRequest and HttpServletResponse +servletcontainer 是附属于webserver的,而这个webserver会持续监听一个目标端口的```HTTP request```请求,这个端口在开发中经常会被设置成8080,而在生产环境会被设置成80。当一个客户端(比如用户的浏览器)发送一个HTTP request,servletcontainer就会创建新的HttpServletRequest对象和HttpServletResponse对象。。。。 + +在有filter的情况下,```doFilter()```方法会被触发。当代码调用```chain.doFilter(request, response)```时候,请求会经过下一个过滤器filter,如果没有了过滤器,会到达servlet。在servlets的情况下,```service()```触发,然后根据```request.getMethod()```确定执行doGet()还是```doPost()```,如果当前servlet找不到请求的方法,返回405error。 + +request对象提供了HTTP请求所有的信息,比如request headers和request body,response对象提供了控制和发送HTTP响应的的能力,并且以你想要的方式,比如设置headers和body。当HTTP响应结束,请求和响应对象会被销毁(实际上,大多数container将会清洗到这些对象的状态然后回收这些事例以重新利用) +####httpSession +当客户端第一次访问webapp或者通过```request.getSession()```方法第一次获取httpSession +,servletcontainer 将会创建一个新的HttpSession 对象,产生一个长的唯一的ID标记session(可以通过session.getId()),并且将这个session存储在server内存中。servletcontainer 同时会在HTTP response的Header中设置```Set-Cookie```cookie值,其中cookie name为JSESSIONID,cookie value为唯一的长ID值。 + +在接下来的连续请求中,客户端浏览器都要cookie通过header带回,然后servletcontainer 会根据cookie中的JSESSIONID 值,获得server内存中的对应的httpSession。 + +只要没超过``````设定的值,httpSession对象会一直存在,``````大小可以在web.xml中设定,默认是30分钟。所以如果连续30分钟之内客户端不再访问webapp,servletcontainer就会销毁对应的session。接下来的request请求即使cookies依旧存在,但是却不再有对应的session了。servletcontainer 会创建新的session。 + +另外一方面,session cookie在浏览器端有默认的生命时长,就是只要浏览器一直在运行,所以当浏览器关闭,浏览器端的cookie会被销毁。 +####最后 +- 只要webapp存在,ServletContext 一定会存在。并且ServletContext 是被所有session和request共享的。 +- 只要客户端用同一个浏览器和webapp交互并且该session没有在服务端超时,HttpSession 就会一直存在。并且在同一个会话中所有请求都是共享的。 +- 只有当完整的response响应到达,HttpServletRequest 和 HttpServletResponse才不再存活,并且不被共享。 +- 只要webapp存在,servlet、filter和listener就会存在。他们被所有请求和会话共享。 +- 只要问题中的对象存在,任何设置在ServletContext, HttpServletRequest 和 HttpSession中的属性就会存在。 + +####线程安全 +就是说,你主要关注的是线程安全性。你应该了解到,servlets和filter是被所有请求共享的。这正是Java的美妙之处,它的多线程和不同的线程可以充分利用同样的实例instance,否则对于每一个request请求都要重复创建和调用init()和destroy()开销太大。 + +但是你也应该注意到,你不应该把任何请求或会话作用域的数据作为一个servlet或过滤器的实例变量。这样会被其他会话的请求共享,并且那是线程不安全的!下面的例子阐明的这点: +``` +public class ExampleServlet extends HttpServlet { + + private Object thisIsNOTThreadSafe; + + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + Object thisIsThreadSafe; + + thisIsNOTThreadSafe = request.getParameter("foo"); // BAD!! Shared among all requests! + thisIsThreadSafe = request.getParameter("foo"); // OK, this is thread safe. + } +} +``` + +stackoverflow链接: + +http://stackoverflow.com/questions/3106452/how-do-servlets-work-instantiation-shared-variables-and-multithreading \ No newline at end of file diff --git a/contents/how-do-you-assert-that-a-certain-exception-is-thrown-in-junit-4-tests.md b/contents/how-do-you-assert-that-a-certain-exception-is-thrown-in-junit-4-tests.md new file mode 100644 index 0000000..6c5cbdf --- /dev/null +++ b/contents/how-do-you-assert-that-a-certain-exception-is-thrown-in-junit-4-tests.md @@ -0,0 +1,63 @@ +## JUnit4如何断言确定异常的抛出 + +#### 问题 + +在JUnit4单元测试中,我要怎样做才能测试出有特定的异常抛出?我能想到的就只有下面的方法: + +```java +@Test +public void testFooThrowsIndexOutOfBoundsException() { + boolean thrown = false; + + try { + foo.doStuff(); + } catch (IndexOutOfBoundsException e) { + thrown = true; + } + + assertTrue(thrown); +} +``` + +#### 回答1 + +在JUnit4后支持下面的写法: +```java +@Test(expected=IndexOutOfBoundsException.class) +public void testIndexOutOfBoundsException() { + ArrayList emptyList = new ArrayList(); + Object o = emptyList.get(0); +} +``` +(译者:在`@Test`注解内提供了`expected`属性,你可以用它来指定一个`Throwble`类型,如果方法调用中抛出了这个异常,那么这条测试用例就相当于通过了) + +#### 回答2 + +如果你使用的是JUnit4.7,你可以使用如下的期望异常规则来验证异常信息: + +```java +public class FooTest { + @Rule + public final ExpectedException exception = ExpectedException.none(); + + @Test + public void doStuffThrowsIndexOutOfBoundsException() { + Foo foo = new Foo(); + + exception.expect(IndexOutOfBoundsException.class); + foo.doStuff(); + } +} +``` + +这种方式比`@Test(expected=IndexOutOfBoundsException.class)`要更好,如果是在调用`foo.doStuff()`方法之前就已经抛出异常的话,测试结果就不是我们想要的了。 +(译者:同时,`ExpectedException`还能够验证异常信息,如`exception.expectMessage("there is an exception!");` + +#### 拓展阅读 + +1. [JUnit:使用ExpectedException进行异常测试](http://www.tuicool.com/articles/ANviIz) +2. [JUnit4 用法详解](http://www.blogjava.net/jnbzwm/archive/2010/12/15/340801.html) + +#### StackOverflow地址: + +[http://stackoverflow.com/questions/156503/how-do-you-assert-that-a-certain-exception-is-thrown-in-junit-4-tests](http://stackoverflow.com/questions/156503/how-do-you-assert-that-a-certain-exception-is-thrown-in-junit-4-tests) \ No newline at end of file diff --git a/contents/how-does-the-java-for-each-loop-work.md b/contents/how-does-the-java-for-each-loop-work.md new file mode 100644 index 0000000..8d58d0f --- /dev/null +++ b/contents/how-does-the-java-for-each-loop-work.md @@ -0,0 +1,23 @@ +## Java的foreach循环是如何工作的? +### 问题 +````java +List someList = new ArrayList(); +// add "monkey", "donkey", "skeleton key" to someList +for (String item : someList) { + System.out.println(item); +} +```` +如果不用for each语法,等价的循环语句是什么样的? +### 回答 +````java +for(Iterator i = someList.iterator(); i.hasNext(); ) { + String item = i.next(); + System.out.println(item); +} +```` +记住,如果需要在循环中使用i.remove;或者以某种方式获取实际的iterator,你不能使用for(:)语法,因为实际的Iterator很难被推断出来。 +正如Denis Bueno写的那样,这种代码对任何实现了Iterable接口的对象都奏效。 +此外,如果for(:)句法中右侧是一个数组而不是一个可迭代对象,那么内部代码用一个int型的计数器来防止数组越界。详见Java Language Specification: +http://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.14.2 + +stackoverflow链接:http://stackoverflow.com/questions/85190/how-does-the-java-for-each-loop-work diff --git a/contents/how-to-create-a-generic-array-in-java.md b/contents/how-to-create-a-generic-array-in-java.md new file mode 100644 index 0000000..086f0d2 --- /dev/null +++ b/contents/how-to-create-a-generic-array-in-java.md @@ -0,0 +1,80 @@ +## 如何创建泛型java数组 + +#### 问题 + +数组是不能通过泛型创建的,因为我们不能创建不可具体化的类型的数组。如下面的代码: + +```java +public class GenSet { + private E a[]; + + public GenSet() { + a = new E[INITIAL_ARRAY_LENGTH]; //编译期就会报错:不能创建泛型数组 + } +} +``` + +#### 采纳答案 + +* 检查:强类型。`GenSet`明确知道数组中包含的类型是什么(例如通过构造器传入`Class`,当方法中传入类型不是`E`将抛出异常) + +```java +public class GenSet { + + private E[] a; + + public GenSet(Class c, int s) { + // 使用原生的反射方法,在运行时知道其数组对象类型 + @SuppressWarnings("unchecked") + final E[] a = (E[]) Array.newInstance(c, s); + this.a = a; + } + + E get(int i) { + return a[i]; + } + + //...如果传入参数不为E类型,那么强制添加进数组将会抛出异常 + void add(E e) {...} +} +``` + +* 未检查:弱类型。数组内对象不会有任何类型检查,而是作为Object类型传入。 + +在这种情况下,你可以采取如下写法: + +```java +public class GenSet { + + private Object[] a; + + public GenSet(int s) { + a = new Object[s]; + } + + E get(int i) { + @SuppressWarnings("unchecked") + final E e = (E) a[i]; + return e; + } +} +``` + +上述代码在编译期能够通过,但因为泛型擦除的缘故,在程序执行过程中,数组的类型有且仅有`Object`类型存在,这个时候如果我们强制转化为`E`类型的话,在运行时会有`ClassCastException`抛出。所以,要确定好泛型的上界,将上边的代码重写一下: + +```java +public class GenSet { // E has an upper bound of Foo + + private Foo[] a; // E 泛型在运行期会被擦除为Foo类型,所以这里使用Foo[] + + public GenSet(int s) { + a = new Foo[s]; + } + + //... +} +``` + +#### StackOverflow地址: + +[http://stackoverflow.com/questions/529085/how-to-create-a-generic-array-in-java](http://stackoverflow.com/questions/529085/how-to-create-a-generic-array-in-java) \ No newline at end of file diff --git a/contents/is-null-check-needed-before-calling-instanceof.md b/contents/is-null-check-needed-before-calling-instanceof.md new file mode 100644 index 0000000..d7a8008 --- /dev/null +++ b/contents/is-null-check-needed-before-calling-instanceof.md @@ -0,0 +1,47 @@ +## 在调用 instanceof 前需要进行null检查吗 + + +### 问题: + +null instanceof SomeClass 会返回 null 还是抛出 NullPointerException 异常 + +### 答案一 +在调用 instanceof 前不要进行null检查 +null instanceof SomeClass 会返回 null +在 Java Language Specification 中 http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.20.2 + +``` +在运行时,如果该instanceof运算符的关系表达式(RelationExpression)不为 null,且这个引用可以被成功转型( §15.16),不抛出ClassCastException,则结果为true; + 否则结果为false。 +``` + +### 答案二 + public class IsInstanceOfTest { + + public static void main(final String[] args) { + + String s; + + s = ""; + + System.out.println((s instanceof String)); + System.out.println(String.class.isInstance(s)); + + s = null; + + System.out.println((s instanceof String)); + System.out.println(String.class.isInstance(s)); + } + } +打印出 + + true + true + false + false + +### 原文链接 +http://stackoverflow.com/questions/2950319/is-null-check-needed-before-calling-instanceof + + + \ No newline at end of file diff --git a/contents/iterating-through-a-collection-avoiding-concurrentmodificationexception-when-re.md b/contents/iterating-through-a-collection-avoiding-concurrentmodificationexception-when-re.md new file mode 100644 index 0000000..47195c4 --- /dev/null +++ b/contents/iterating-through-a-collection-avoiding-concurrentmodificationexception-when-re.md @@ -0,0 +1,69 @@ +## 遍历集合时移除元素,怎样避免ConcurrentModificationException异常抛出 + +#### 问题: + +在遍历集合的过程中,不会总出现`ConcurrentModificationException`异常的抛出,但是在下面的代码块中: + +```java +public static void main(String[] args) { + Collection l = new ArrayList(); + + for (int i=0; i < 10; ++i) { + l.add(new Integer(4)); + l.add(new Integer(5)); + l.add(new Integer(6)); + } + + //遍历的过程中移除部分集合元素 + for (Integer i : l) { + if (i.intValue() == 5) { + l.remove(i); + } + } + + System.out.println(l); +} +``` + +运行之后,结果显而易见,总是会抛出异常: + +```java +Exception in thread "main" java.util.ConcurrentModificationException +``` + +所以,遍历集合时移除元素,怎样避免ConcurrentModificationException异常的产生?有什么好的解决办法? + +#### 回答: + +`Iterator.remove()`是线程安全的,所以你的代码可以这样写: + +```java +List list = new ArrayList(); + +for (Iterator iterator = list.iterator(); iterator.hasNext();) { + String string = iterator.next(); + if (string.isEmpty()) { + + // 从迭代器中移除集合元素,集合中相应的集合元素也会安全地被移除 + // 在这里,如果继续调用的是list.remove(string),那么仍会抛出异常 + iterator.remove(); + } +} +``` + +在遍历集合时修改集合的结构或内容的情况中,`Iterator.remove()`是唯一线程安全的方法。 + +#### 问题原因: + +fail-fast, 快速失败机制,是java集合类的一种错误检查机制。当有多个线程同时对集合进行遍历以及内容或者结构的修改时,就有可能产生fail-fast机制。这意味着,当它们发现容器在迭代的过程中被修改时,就会抛出一个ConcurrentModificationException异常。 + +迭代器的快速失败行为无法得到保证,它不能保证一定会出现该错误,但是快速失败操作会尽最大努力抛出ConcurrentModificationException异常,这个异常仅用于检测bug。这种迭代器并不是完备的处理机制,而只是作为并发问题的一个预警指示器。 + + +#### 拓展阅读: + +[fail-fast机制的原理解析](https://github.com/AcceptedBoy/backstage-vacation-plan/blob/master/chapter1/concurrency/fail-fast.md) + +#### StackOverFlow地址: + +[http://stackoverflow.com/questions/223918/iterating-through-a-collection-avoiding-concurrentmodificationexception-when-re](http://stackoverflow.com/questions/223918/iterating-through-a-collection-avoiding-concurrentmodificationexception-when-re) \ No newline at end of file diff --git a/contents/java-inner-class-and-static-nested-class.md b/contents/java-inner-class-and-static-nested-class.md new file mode 100644 index 0000000..e6d08c2 --- /dev/null +++ b/contents/java-inner-class-and-static-nested-class.md @@ -0,0 +1,44 @@ +## Java内部类和嵌套静态类 + +### 问题 +Java 当中的内部类和静态嵌套类有什么主要区别? 在这两者中有什么设计或者实现么? + +### 回答 +嵌套类分为两类: 静态和非静态. 用`static`装饰的嵌套类叫做静态类, 非静态的嵌套类叫做内部类. + +静态嵌套类使用外围类名来访问: +```java +OuterClass.StaticNestedClass +``` +例如, 实例化一个静态嵌套类的对象就要使用这种语法: +```java +OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass(); +``` + +内部类对象的存在需要依靠一个外部类的对象. 看看下面的类: +```java +class OuterClass { + ... + class InnerClass { + ... + } +} +``` +内部类对象只有当外部类对象存在时才有效, 并且可以直接访问他的包裹对象(外部类对象)的方法以及成员. + +因此, 要实例化一个内部类对象, 必须先实例化外部类对象. 然后用这种语法来创建内部类对象: +```java +OuterClass.InnerClass innerObject = outerObject.new InnerClass(); +``` +参考: [Java Tutorial - Nested Classes](http://download.oracle.com/javase/tutorial/java/javaOO/nested.html) + +提醒一下, 还有一种不用外部类对象来创建内部类对象的方法: [inner class without an enclosing ](http://stackoverflow.com/questions/20468856/is-it-true-that-every-inner-class-requires-an-enclosing-instance) +```java +class A { + int t() { return 1; } + static A a = new A() { int t() { return 2; } }; +} +``` +在这里, `new A() { ... }`是一个定义在静态上下文的内部类对象, 并没有一个外围对象. + +stackoverflow链接: [Java inner class and static nested class](http://stackoverflow.com/questions/70324/java-inner-class-and-static-nested-class) diff --git a/contents/lookup-enum-by-string-value.md b/contents/lookup-enum-by-string-value.md new file mode 100644 index 0000000..160aafa --- /dev/null +++ b/contents/lookup-enum-by-string-value.md @@ -0,0 +1,107 @@ +Java 中如何将 String 转换为 enum +======= + +###问题 + +###我有一个 enum 类 + +``` java +public enum Blah { + A, B, C, D +} +``` +我想要找到一个 `String` 对应的 enum 值。例如, `"A"` 将是 `Blah.A`.如何做到? + +我需要使用 `Enum.valueOf()` 方法吗? 如果是该如何使用? + +--- + +### A1 + +是的, `Blah.valueOf("A")` 将会给你 `Blah.A`. + +静态方法 `valueof()` 和 `values()` 在编译时期被插入,并不存在于源码中。但是在Javadoc中;例如,[`Dialog.ModalityType`](http://docs.oracle.com/javase/7/docs/api/java/awt/Dialog.ModalityType.html "Dialog.ModalityType")中显示了这两个方法。 + + +### A2 + +另一个解答,如果文本和 `enumeration` 值不一致 + +``` java +public enum Blah { + A("text1"), + B("text2"), + C("text3"), + D("text4"); + + private String text; + + Blah(String text) { + this.text = text; + } + + public String getText() { + return this.text; + } + + public static Blah fromString(String text) { + if (text != null) { + for (Blah b : Blah.values()) { + if (text.equalsIgnoreCase(b.text)) { + return b; + } + } + } + return null; + } +} +``` +_评论区在讨论是应该返回null还是抛出异常,个人认为视具体情况,允许转换失败就返回null,不允许就抛出异常,或许创建一个特殊的空对象是个好的选择 -译者注_ + +### A3 + +这是我使用的一个工具类: + +``` java +/** + * 一个对于所有Enum类通用的方法,因为他们不能有另一个基类 + * @param Enum type + * @param c enum type. All enums must be all caps. + * @param string case insensitive + * @return corresponding enum, or null + */ +public static > T getEnumFromString(Class c, String string) { + if( c != null && string != null ) { + try { + return Enum.valueOf(c, string.trim().toUpperCase()); + } catch(IllegalArgumentException ex) { + } + } + return null; +} +``` +之后,在我的enum类中通常如此使用来减少打字: +``` java +public static MyEnum fromString(String name) { + return getEnumFromString(MyEnum.class, name); +} +``` +如果的enums不是全部大写,只需要修改 `Enum.valueOf` 这一行。 +很遗憾,我不能使用 `T.class` 传给 `Enum.valueOf`,因为 `T`会被擦出。 + +_评论区对于答主的异常处理一片指责 -译者注_ + +###A4 +如果你不想编写自己的工具类,可以使用 Google的 `guava` 库: +``` java +Enums.getIfPresent(Blah.class, "A") +``` +它让你检查是否 `Blan`中存在 `A`并且不抛出异常 + +_完整方法签名 `Optional getIfPresent(Class enumClass, String value)` , `Optional` 对象可以优雅的解决null值问题 -译者注_ + +--- +_其他的答案都大同小异,感兴趣的可以看原帖_ +stackoverflow链接 +http://stackoverflow.com/questions/604424/lookup-enum-by-string-value +_译者:[MagicWolf](https://github.com/DaiDongLiang)_ diff --git a/contents/what-is-a-serialversionuid-and-why-should-i-use-it.md b/contents/what-is-a-serialversionuid-and-why-should-i-use-it.md index 645bd54..321c58a 100644 --- a/contents/what-is-a-serialversionuid-and-why-should-i-use-it.md +++ b/contents/what-is-a-serialversionuid-and-why-should-i-use-it.md @@ -127,7 +127,7 @@ public void testversion1LWithExtraEmail() throws Exception { private static final long serialVersionUID = 2L; ``` -再次进行序列化,则会报错,如下: +再次进行反序列化,则会报错,如下: ``` java.io.InvalidClassException:Person local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2 ``` diff --git a/contents/what-is-the-difference-between-a-soft-reference-and-a-weak-reference-in-java.md b/contents/what-is-the-difference-between-a-soft-reference-and-a-weak-reference-in-java.md new file mode 100644 index 0000000..eb01281 --- /dev/null +++ b/contents/what-is-the-difference-between-a-soft-reference-and-a-weak-reference-in-java.md @@ -0,0 +1,38 @@ +# Java中软引用和弱引用的区别 +## 问题 +题目就是问题 + +## 解答 +### 回答1 +从Ethan Nicholas的《Understanding Weak References》中 + +弱引用: +放置一个弱引用的作用,不是强有力强制一个对象保存在内存中。弱引用允许利用垃圾收集者的能力去决定可达性,所以你不需要自己做,你只需要创建一个软引用: + + WeakReference weakWidgt = new WeakReference(widgt); + +然后在代码别的地方你可以使用 `weakWidget.get()` 来获取真实的 `Widgt` 对象,当然弱引用足以强大能抵制垃圾收集器,所以你也许发现(如果没有强引用指向widget)`weakWidget.get()`突然开始返回null + +软引用 + +软引用就像弱引用一样,除了它不会着急将引用的对象扔出去。只有弱可达性的对象(这样的对象最强的引用只能是弱引用)将在下一次垃圾收集处理中被抛弃,但是软可达性的对象通常可以坚持一会。 + +软引用不要求与弱引用有什么不同,但是实际中,只要内存足够,软可达的对象通常会维持下去。对于缓存来说,这是个不错的基础,就像以上图像缓存描述,虽然可以让垃圾收集者担心对象是如何可达(一个强可达性的对象从不会从缓存中移除)和她们需要消耗多少内存 + +而且Peter Kessler备注到 + +Sun JRE 对待软引用和弱引用是不同的。如果内存是够用的。我们应坚持用软引用引用对象。一个细节是:对于客户端和服务器,JRE的政策是不同的:客户端,JRE试图保持通过清除软引用而不是扩大堆内存来使改变小点,而服务器端,JRE通过扩大堆内存让性能更好。没有一种通用的方法。 + +### 回答2 +弱引用对象很快被收集。如果GC发现一个对象是弱引用(只能通过弱引用可达),它会立刻清除弱引用对象。同样的,对于在程序保持关联信息的对象保持一个引用是不错的,像关于类的缓存存储的反射信息或一个对象的包装器等等。没有意义地跟随相连对象的任何事物都会被清除掉。当弱引用清除掉时,它会进入到引用队列中,同时丢弃关联的对象。你保持关于对象额外的信息,但是一旦对象引用不要了,信息也就不需要了。总之,在某些情境下,你可以创建WeakReference的子类,保持在WeakReference的子类中对象的额外信息。WeakReference的其他典型应用是与Map连接,以保持规范化的例子。 + +在另一方面,软引用有利于外部缓存,再创造资源,因为GC会延迟清理他们。它能保证所有软引用会在内存溢出之前被清除,所以它们不会造成内存溢出。 + +典型的使用例子是保持从一个文件内容解析形式。在你载入文件,解析和与解析过代表的根对象保持一个软引用的地方扩展系统。在你下次需要文件时,你试图通过软引用恢复。如果可以恢复,你会在其他地方载入、解析你分享的文件,如果同时GC清理掉,你也可以重新载入。这样的话,你利用空内存可以做到性能最优化,但是不要内存溢出。 +光保持一个软引用不会造成溢出。如果在另一方面你误用软引用,且弱引用被使用了(也就是说,你保持与较强引用的对象相连的信息,然后当引用对象被清除,你也丢弃信息),你可能会内存溢出,因为在进入引用队列时,也许碰巧没有及时丢弃相连的对象。 + +所以,使用软引用还是弱引用是取决于用法的。如果你的信息构造起来较为复杂,但是尽管如此仍想从别的数据再构造信息,使用软引用。如果你对一些数据的规范化实例保持引用,或者你想对一个"不拥有的"对象保持引用(就是防止被垃圾回收),这样就使用弱引用。 + + +原文: +> http://stackoverflow.com/questions/299659/what-is-the-difference-between-a-soft-reference-and-a-weak-reference-in-java \ No newline at end of file diff --git a/contents/what-is-the-difference-between-jsf-servlet-and-jsp.md b/contents/what-is-the-difference-between-jsf-servlet-and-jsp.md new file mode 100644 index 0000000..93a31c7 --- /dev/null +++ b/contents/what-is-the-difference-between-jsf-servlet-and-jsp.md @@ -0,0 +1,46 @@ +## JSF, Servlet 和 JSP (三种技术)有什么区别? + +###问题 +JSP 和 Servlet 有什么关系?JSP 是某种 Servlet 吗?JSP 和 JSF 又有什么关系?JSF 是某种基于JSP的,预构建好的 UI 吗,像 +ASP.NET-MVC 那样? + + +###回答1 + +#### JSP(Java Server Pages) +JSP 是一种运行在服务器上的Java 视图技术,它允许你写入模版化的文本(例如客户端代码 HTML, CSS, JavaScript等)。JSP 支持标签库(taglibs),标签库由Java 代码实现,让你可以动态地控制页面输出。JSTL 便是一种比较有名的标签库。JSP 同样支持表达式语言(expression language),表达式语言可以用来访问后台数据(页面上可用的属性,request/session 对象等等), 通常与标签库结合使用。 + +当一个 JSP 第一次被访问或者 webapp 启动时,servlet 容器会将 JSP 编译成一个继承了 HttpServlet 的类,然后在整个 webapp 生命周期内使用被编译后的类。可以在 servlet 容器的 work 目录下找到 JSP 对应的源代码。例如Tomcat 的 CATALINA.BASE/work 目录。 +当收到一个 JSP 请求时,servlet 容器会执行编译 JSP 生成的类,并将该类的输出(通常是 HTML/CSS/JS)发送到 客户端,客户端(WEB 浏览器) 会展示从服务端收到的内容。 + +#### Servlet +Servlet 是一种针对服务器端的 API,它用来响应客户端请求,并生成响应。比较有名的例子是 HttpServlet,它提供了响应 HTTP 请求(例如 GET POST)的方法。你可以从 web.xml 配置 HttpServlet 来监听某种 HTTP URL pattern 的请求,或者使用较新的 Java EE 6 @WebServlet 注解。 + +当 Servlet 第一次被请求,或者 webapp 启动时,servlet 容器会创建该 Servlet 的实例,并在整个 webapp 的生命周期维持该实例在内存中。同一个实例会被复用,来响应匹配到 URL pattern 的请求。可以通过 HttpServletRequest 访问请求里的数据,通过 HttpServletResponse 控制响应。上边两个对象会是 HttpServlet 的重载方法 doGet()和 doPost() 的参数。 + +#### JSF (JavaServer Faces) +JSF 是一个基于组件的MVC框架,建立在 Servlet API 基础上,JSF 通过标签库提供组件,标签库又可以用于 JSP 或者其它 Java 视图技术例如 Facelets. Facelets 更适合JSF。即它提供了很厉害的模版功能例如组合组件,而JSP 基本上只提供了 `` 来支持模版,所以 +当你想用一个组件替换一组重复出现的组件时,你不得不使用原生的 Java 代码来创建自定义组件(这在 JSF 里并不那么清晰明了,而且带来很多冗余工作)。为了推进 Facelets,自从 JSF 2.0 之后,JSP 这种视图技术已经被废弃了。 +作为一种 MVC(Model-View-Controller)框架,JSF 提供了唯一的 FacesServlet 请求/响应控制器。它负责所有的 HTTP 请求/响应工作, +例如 收集/校验/转换用户输入,将输入设置到 model 对象里,调用处理逻辑并输出响应。这样你基本上 只有一个 JSP或者 Facelets(XHTML) 页面用作视图,再加一个 Javabean 类当作 模型。 JSF 组件用来将模型和视图绑定起来(类似 ASP.NET web control 做的),然后 FacesServlet 使用 JSF 组件树来完成整个工作。 + +### 其它答案选编 + +参考以下链接 + +[http://www.oracle.com/technetwork/java/faq-137059.html](http://www.oracle.com/technetwork/java/faq-137059.html) + +[https://jcp.org/en/introduction/faq](https://jcp.org/en/introduction/faq) + +JSP 是一种特殊的Servlet。 + +JSF 是一个可以配合 JSP 使用的标签集。 + + +### stackoverflow原文链接: +[http://stackoverflow.com/questions/2095397/what-is-the-difference-between-jsf-servlet-and-jsp](http://stackoverflow.com/questions/2095397/what-is-the-difference-between-jsf-servlet-and-jsp) + + + + + diff --git a/contents/what-issues-should-be-considered-when-overriding-equals-and-hashcode-in-java.md b/contents/what-issues-should-be-considered-when-overriding-equals-and-hashcode-in-java.md index 1ed4300..f09120b 100644 --- a/contents/what-issues-should-be-considered-when-overriding-equals-and-hashcode-in-java.md +++ b/contents/what-issues-should-be-considered-when-overriding-equals-and-hashcode-in-java.md @@ -1,4 +1,4 @@ -##重写(Override)equlas和hashCode方法时应考虑的问题 +##重写(Override)equals和hashCode方法时应考虑的问题 ###理论上讲(编程语言、数学层面) equals() 定义了对象的相等关系(自反性、对称性、传递性)(有点抽象,更详细说明,请参考[javadoc](http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object))) 。 diff --git a/contents/whats-the-difference-between-component-repository-service-annotations-in.md b/contents/whats-the-difference-between-component-repository-service-annotations-in.md new file mode 100644 index 0000000..0dd4196 --- /dev/null +++ b/contents/whats-the-difference-between-component-repository-service-annotations-in.md @@ -0,0 +1,77 @@ +## @Component, @Repository, @Service的区别 + +#### 问题 + +在spring集成的框架中,注解在类上的`@Component`,`@Repository`,`@Service`等注解能否被互换?或者说这些注解有什么区别? + +#### 回答1 + +引用spring的官方文档中的一段描述: + +在Spring2.0之前的版本中,`@Repository`注解可以标记在任何的类上,用来表明该类是用来执行与数据库相关的操作(即dao对象),并支持自动处理数据库操作产生的异常 + +在Spring2.5版本中,引入了更多的Spring类注解:`@Component`,`@Service`,`@Controller`。`Component`是一个通用的Spring容器管理的单例bean组件。而`@Repository`, `@Service`, `@Controller`就是针对不同的使用场景所采取的特定功能化的注解组件。 + +因此,当你的一个类被`@Component`所注解,那么就意味着同样可以用`@Repository`, `@Service`, `@Controller`来替代它,同时这些注解会具备有更多的功能,而且功能各异。 + +最后,如果你不知道要在项目的业务层采用`@Service`还是`@Component`注解。那么,`@Service`是一个更好的选择。 + +就如上文所说的,`@Repository`早已被支持了在你的持久层作为一个标记可以去自动处理数据库操作产生的异常(译者注:因为原生的java操作数据库所产生的异常只定义了几种,但是产生数据库异常的原因却有很多种,这样对于数据库操作的报错排查造成了一定的影响;而Spring拓展了原生的持久层异常,针对不同的产生原因有了更多的异常进行描述。所以,在注解了`@Repository`的类上如果数据库操作中抛出了异常,就能对其进行处理,转而抛出的是翻译后的spring专属数据库异常,方便我们对异常进行排查处理)。 + +| 注解 | 含义 | +| ------------- |:-------------:| +| @Component | 最普通的组件,可以被注入到spring容器进行管理 | +| @Repository | 作用于持久层 | +| @Service | 作用于业务逻辑层 | +| @Controller | 作用于表现层(spring-mvc的注解) | + +#### 回答2 + +这几个注解几乎可以说是一样的:因为被这些注解修饰的类就会被Spring扫描到并注入到Spring的bean容器中。 + +这里,有两个注解是不能被其他注解所互换的: + +* `@Controller` 注解的bean会被spring-mvc框架所使用。 +* `@Repository` 会被作为持久层操作(数据库)的bean来使用 + +如果想使用自定义的组件注解,那么只要在你定义的新注解中加上`@Component`即可: + +```java +@Component +@Scope("prototype") +public @interface ScheduleJob {...} +``` + +这样,所有被`@ScheduleJob`注解的类就都可以注入到spring容器来进行管理。我们所需要做的,就是写一些新的代码来处理这个自定义注解(译者注:可以用反射的方法),进而执行我们想要执行的工作。 + +#### 回答3 + +`@Component`就是跟``一样,可以托管到Spring容器进行管理。 + +@Service, @Controller , @Repository = {@Component + 一些特定的功能}。这个就意味着这些注解在部分功能上是一样的。 + +当然,下面三个注解被用于为我们的应用进行分层: + +* `@Controller`注解类进行前端请求的处理,转发,重定向。包括调用Service层的方法 +* `@Service`注解类处理业务逻辑 +* `@Repository`注解类作为DAO对象(数据访问对象,Data Access Objects),这些类可以直接对数据库进行操作 + +有这些分层操作的话,代码之间就实现了松耦合,代码之间的调用也清晰明朗,便于项目的管理;假想一下,如果只用`@Controller`注解,那么所有的请求转发,业务处理,数据库操作代码都糅合在一个地方,那这样的代码该有多难拓展和维护。 + +#### 总结 + +* `@Component`, `@Service`, `@Controller`, `@Repository`是spring注解,注解后可以被spring框架所扫描并注入到spring容器来进行管理 +* `@Component`是通用注解,其他三个注解是这个注解的拓展,并且具有了特定的功能 +* `@Repository`注解在持久层中,具有将数据库操作抛出的原生异常翻译转化为spring的持久层异常的功能。 +* `@Controller`层是spring-mvc的注解,具有将请求进行转发,重定向的功能。 +* `@Service`层是业务逻辑层注解,这个注解只是标注该类处于业务逻辑层。 +* 用这些注解对应用进行分层之后,就能将请求处理,义务逻辑处理,数据库操作处理分离出来,为代码解耦,也方便了以后项目的维护和开发。 + +#### Stackoverflow链接: + +[http://stackoverflow.com/questions/6827752/whats-the-difference-between-component-repository-service-annotations-in](http://stackoverflow.com/questions/6827752/whats-the-difference-between-component-repository-service-annotations-in) + +#### 拓展 + +1. [Spring注解@Component、@Repository、@Service、@Controller区别](http://www.cnblogs.com/JAYIT/p/5593169.html) +2. [Spring注解@Autowired、@Resource区别](http://www.cnblogs.com/leiOOlei/p/3713779.html) \ No newline at end of file diff --git a/contents/when-and-how-should-i-use-a-threadlocal-variable.md b/contents/when-and-how-should-i-use-a-threadlocal-variable.md new file mode 100644 index 0000000..50d97ef --- /dev/null +++ b/contents/when-and-how-should-i-use-a-threadlocal-variable.md @@ -0,0 +1,33 @@ +## 该什么时候使用 ThreadLocal变量,它是如何工作的? +### 回答1 +一种可能的(也是常见的)使用情形是你不想通过同步方式(synchronized)访问非线程安全的对象(说的就是SimpleDateFormat),而是想给每个线程一个对象实例的时候。 +例如 +````java +public class Foo +{ + // SimpleDateFormat is not thread-safe, so give one to each thread + private static final ThreadLocal formatter = new ThreadLocal(){ + @Override + protected SimpleDateFormat initialValue() + { + return new SimpleDateFormat("yyyyMMdd HHmm"); + } + }; + + public String formatIt(Date date) + { + return formatter.get().format(date); + } +} +```` +### 回答2 +因为ThreadLocal是一个既定线程内部的数据引用,你可能在使用线程池的应用服务器上因此引起类加载时候的内存泄漏。你需要使用remove()方法很小心地清理TheadLocal中get()或者set()的变量。 +如果程序执行完毕没有清理的话,它持有的任何对类的引用将作为部署的Web应用程序的一部分仍保持在永久堆,永远无法得到回收。重新部署/取消部署也无法清理对应用程序类的引用,因为线程不是被你的应用程序所拥有的。 +每次成功部署都会创建一个永远不会被垃圾回收类的实例。 + +最后将会遇到内存不足的异常-java.lang.java.lang.OutOfMemoryError: PermGen space -XX:MaxPermSize,在google了很多答案之后你可能只是增加了-XX:MaxPermSize,而不是修复这个bug。 +倘若你的确遇到这种问题,可以通过[Eclipse's Memory Analyzer](http://www.eclipse.org/mat/)或根据[Frank Kieviet's guide](https://blogs.oracle.com/fkieviet/entry/classloader_leaks_the_dreaded_java) 和 [followup](https://blogs.oracle.com/fkieviet/entry/how_to_fix_the_dreaded)来判断哪些线程和类保留了那些引用。 + +更新:又发现了[Alex Vasseur's blog entry](http://avasseur.blogspot.jp/2003/11/threadlocal-and-memory-leaks.html),它帮助我查清楚了一些ThreadLocal的问题。 + +stackoverflow链接:http://stackoverflow.com/questions/817856/when-and-how-should-i-use-a-threadlocal-variable diff --git a/contents/why-is-java-vector-class-considered-obsolete-or-deprecated.md b/contents/why-is-java-vector-class-considered-obsolete-or-deprecated.md new file mode 100644 index 0000000..cfbb754 --- /dev/null +++ b/contents/why-is-java-vector-class-considered-obsolete-or-deprecated.md @@ -0,0 +1,21 @@ +## 为什么Java的```Vector```类被认为是过时的或者废弃的 +### 问题 +为什么java ```Vector```类被认为是一个遗留的,过时的或废弃的类?在并发操作时,使用它是无效的吗? + +如果我不想手动对对象实现同步,只想用一个线程安全的集合而无需创建底层数组的全新副本(如```CopyOnWriteArrayList```一样)。这种情况下,我使用```Vector```合理吗? + +然后就是关于栈的问题,它是Vector的一个子类,我应该用什么代替它? +### 回答 +Vector中对每一个独立操作都实现了同步,这通常不是我们想要的做法。对单一操作实现同步通常不是线程安全的(举个例子,比如你想遍历一个Vector实例。你仍然需要申明一个锁来防止其他线程在同一时刻修改这个Vector实例。如果不添加锁的话 + +通常会在遍历实例的这个线程中导致一个``` ConcurrentModificationException ```)同时这个操作也是十分慢的(在创建了一个锁就已经足够的前提下,为什么还需要重复的创建锁) + +当然,即使你不需要同步,Vector也是有锁的资源开销的。 + +总的来说,在大多数情况下,这种同步方法是存在很大缺陷的。正如Mr Brain Henk指出,你可以通过调用```Collections.synchronizedList```来装饰一个集合 -事实上 ```Vector``` 将"可变数组"的集合实现与"同步每一个方法"结合起来的做法是另一个糟糕的设计; + +各个装饰方法能够更明确的指示其关注的功能实现。 + +对于```Stack```这个类-我更乐于使用```Deque/ArrayDeque```来实现 + +stackoverflow讨论地址: http://stackoverflow.com/questions/1386275/why-is-java-vector-class-considered-obsolete-or-deprecated diff --git a/contents/why-is-printing-b-dramatically-slower-than-printing.md b/contents/why-is-printing-b-dramatically-slower-than-printing.md new file mode 100644 index 0000000..970dbde --- /dev/null +++ b/contents/why-is-printing-b-dramatically-slower-than-printing.md @@ -0,0 +1,114 @@ +# 为什么打印"B"会明显的比打印"#"慢 + +## 问题 + +我生成了两个`1000`x`1000`的矩阵: + +第一个矩阵:`O`和`#`。 +第二个矩阵:`O`和`B`。 + +使用如下的代码,生成第一个矩阵需要8.52秒: + + Random r = new Random(); + for (int i = 0; i < 1000; i++) { + for (int j = 0; j < 1000; j++) { + if(r.nextInt(4) == 0) { + System.out.print("O"); + } else { + System.out.print("#"); + } + } + + System.out.println(""); + } + + +而使用这段代码,生成第二个矩阵花费了259.152秒: + + Random r = new Random(); + for (int i = 0; i < 1000; i++) { + for (int j = 0; j < 1000; j++) { + if(r.nextInt(4) == 0) { + System.out.print("O"); + } else { + System.out.print("B"); //only line changed + } + } + + System.out.println(""); + } + +如此大的运行时间差异的背后究竟是什么原因呢? + +--- + +正如评论中所建议的,只打印`System.out.print("#");`用时7.8871秒,而`System.out.print("B");`则给出`still printing...`。 + +另外有人指出这段代码对他们来说是正常的, 我使用了[Ideone.com](http://ideone.com),这两段代码的执行速度是相同的。 + +测试条件: + + - 我在Netbeans 7.2中运行测试,由控制台显示输出 + - 我使用了`System.nanoTime()`来计算时间 + +## 解答一 + +*纯粹的推测*是因为你使用的终端尝试使用[单词换行][1]而不是字符换行,并且它认为`B`是一个单词而`#`却不是。所以当它到达行尾并且寻找一个换行的地方的时候,如果是`#`就可以马上换行;而如果是`B`,它则需要花更长时间搜索,因为可能会有更多的内容才能换行(在某些终端会非常费时,比如说它会先输出退格再输出空格去覆盖被换行的那部分字符)。 + +但这都只是纯粹的推测。 + + + [1]: http://en.wikipedia.org/wiki/Word_wrap + + +##解答二 + +我用Eclipse和Netbeans 8.0.2做了测试,他们的Java版本都是1.8;我用了`System.nanoTime()`来计时。 + +##Eclipse: + +我得到了**用时相同的结果** - 大约**1.564秒**。 + +##Netbeans: + +* 使用"#": **1.536秒** +* 使用"B": **44.164秒** + +所以看起来像是Netbeans输出到控制台的性能问题。 + +在做了更多研究以后我发现问题所在是Netbeans [换行][1] 的最大缓存(这并不限于`System.out.println`命令),参见以下代码: + + for (int i = 0; i < 1000; i++) { + long t1 = System.nanoTime(); + System.out.print("BBB......BBB"); \\<-contain 1000 "B" + long t2 = System.nanoTime(); + System.out.println(t2-t1); + System.out.println(""); + } + +每一个循环所花费的时间都不到1毫秒,除了 **每第五个循环**会花掉大约225毫秒。像这样(单位是毫秒): + + BBB...31744 + BBB...31744 + BBB...31744 + BBB...31744 + BBB...226365807 + BBB...31744 + BBB...31744 + BBB...31744 + BBB...31744 + BBB...226365807 + . + . + . + +以此类推。 + +##总结: + +1. 使用Eclipse打印"B"完全没有问题 +1. Netbeans有换行的问题但是可以被解决(因为在Eclipse并没有这个问题)(而不用在B后面添加空格("B "))。 + + [1]: http://en.wikipedia.org/wiki/Line_wrap_and_word_wrap + +stackoverflow原址:http://stackoverflow.com/questions/21947452/why-is-printing-b-dramatically-slower-than-printing diff --git a/contents/why-is-subtracting-these-two-times-in-1927-giving-a-strange-result.md b/contents/why-is-subtracting-these-two-times-in-1927-giving-a-strange-result.md new file mode 100644 index 0000000..d436087 --- /dev/null +++ b/contents/why-is-subtracting-these-two-times-in-1927-giving-a-strange-result.md @@ -0,0 +1,60 @@ +##为什么这两个时间(1927年)相减会得到一个奇怪的结果? + +###问题描述 +如果我运行如下的程序,将两个相距一秒的日期解析成字符串并比较他们。 +``` +public static void main(String[] args) throws ParseException { + SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String str3 = "1927-12-31 23:54:07"; + String str4 = "1927-12-31 23:54:08"; + Date sDt3 = sf.parse(str3); + Date sDt4 = sf.parse(str4); + long ld3 = sDt3.getTime() /1000; + long ld4 = sDt4.getTime() /1000; + System.out.println(ld4-ld3); +} +``` + +输出结果为: +``` +353 +``` + +为什么`ld4-ld3`不是`1`(正如我所期望的那样),而是`353`? + +如果我把时间改变为之后的一秒: +``` +String str3 = "1927-12-31 23:54:08"; +String str4 = "1927-12-31 23:54:09"; +``` + +这时,`ld4-ld3`的结果为`1`. + +java版本: +``` +java version "1.6.0_22" +Java(TM) SE Runtime Environment (build 1.6.0_22-b04) +Dynamic Code Evolution Client VM (build 0.2-b02-internal, 19.0-b04-internal, mixed mode) +``` + +时区: +``` +sun.util.calendar.ZoneInfo[id="Asia/Shanghai", +offset=28800000,dstSavings=0, +useDaylight=false, +transitions=19, +lastRule=null] + +Locale(Locale.getDefault()): zh_CN +``` + +###问题回答 +这是因为1927年11月31日上海的时区改变了。 +观看[此页](http://www.timeanddate.com/time/change/china/shanghai?year=1927)获得更多关于上海1927年的细节。 +这个问题主要是由于在1927年12月31日的午夜,时钟回调了5分钟零52秒。 +所以"1927-12-31 23:54:08"这个时间实际上发生了两次,看上去java将这个时间解析为之后的那个瞬间。 +因此出现了这种差别。 + +这只是美好但奇怪的世界时区中的一个插曲。 + +stackoverflow链接:[Why is subtracting these two times (in 1927) giving a strange result?](http://stackoverflow.com/questions/6841333/why-is-subtracting-these-two-times-in-1927-giving-a-strange-result)

AltStyle によって変換されたページ (->オリジナル) /