1.将数组转化为列表 将数组转化为一个列表时,程序员们经常这样做:
List<String> list = Arrays.asList(arr);
Arrays.asList()会返回一个ArrayList对象,ArrayList类是Arrays的一个私有静态类,而不是java.util.ArrayList类,java.util.Arrays.ArrayList类有set()、get()、contains()方法,但是没有增加元素的方法,所以它的大小是固定的,想要创建一个真正的ArrayList类,你应该这样做:
ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(arr));
ArrayList的构造方法可以接受一个集合类型,刚好它也是java.util.Arrays.ArrayList的超类。
2.判断一个数组是否包含一个值 程序员们经常这样做:
Set<String> set = new HashSet<String>(Arrays.asList(arr));
return set.contains(targetValue);
这段代码起作用,但是没有必要把一个数组转化成列表,转化为列表需要额外的时间。它可以像下面那样简单:
Arrays.asList(arr).contains(targetValue);
或者是:
for(String s:arr){
if(s.equals(targetValue)){
return true;
}
}
return false;
第一种方法比第二种更容易读
3.在一个循环中删除一个列表中的元素 思考下面这一段在循环中删除多个元素的的代码
ArrayList<String> list = new ArrayList<String>(Arrays.asList("a","b","c","d"));
for(int i=0;i<list.size();i++){
list.remove(i);
}
System.out.println(list);
输出结果是:
[b,d]
在这个方法中有一个严重的错误。当一个元素被删除时,列表的大小缩小并且下标变化,所以当你想要在一个循环中用下标删除多个元素的时候,它并不会正常的生效。
你也许知道在循环中正确的删除多个元素的方法是使用迭代,并且你知道java中的foreach循环看起来像一个迭代器,但实际上并不是。考虑一下下面的代码:
ArrayList<String> list = new ArrayList<String>(Arrays.asList("a","b","c","d"));
for(String s:list){
if(s.equals("a")){
list.remove(s);
}
}
它会抛出一个ConcurrentModificationException异常。
相反下面的显示正常:
ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b",
"c", "d"));
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
String s = iter.next();
if (s.equals("a")) {
iter.remove();
}
}
.next()必须在.remove()之前调用。在一个foreach循环中,编译器会使.next()在删除元素之后被调用,因此就会抛出ConcurrentModificationException异常,你也许希望看一下ArrayList.iterator()的源代码。
4.Hashtable与HashMap的对比 就算法而言,哈希表是数据结构的一个名字。但是在java中,这个数据结构的名字是HashMap。Hashtable与HashMap的一个重要不同点是Hashtable是同步的。所以你经常不需要Hashtable,相反HashMap经常会用到。
具体请看:
HashMap vs. TreeMap vs. Hashtable vs. LinkedHashMap
Top 10 questions about Map
5.在集合中使用原始类型 在Java中原始类型与无界通配符类型很容易混合在一起,拿Set来说,Set是一个原始类型,而Set<?>是无界的通配符类型。
考虑下面使用原始类型List作为参数的代码:
public static void add(List list,Object o){
list.add(o);
}
pulbic static void main(String[] args){
List<String> list = new ArrayList<String>();
add(list,10);
String s = list.get(0);
这段代码会抛出一个异常:
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at ...
使用原生类型集合是危险的,这是因为原生类型集合跳过了泛型类型检查,并且不是安全的,在Set、Set<?>和Set<Object>中有很大的不同,具体请看Raw type vs. Unbounded wildcard和Type Erasure。
6.访问级别 程序员们经常使用public作为类字段的修饰符,可以很简单的通过引用得到值,但这是一个坏的设计,按照经验,分配给成员变量的访问级别应该尽可能的低。
具体请看:public, default, protected, and private
7.ArrayList与LinkedList的对比 当程序员们不知道ArrayList与LinkedList的区别时,他们经常使用ArrayList,因为它看起来比较熟悉。
然而,它们之前有巨大的性能差别。简而言之,如果有大量的增加删除操作并且没有很多的随机访问元素的操作,应该首先LinkedList。
如果你刚接触它们,请查看ArrayList vs. LinkedList来获得更多关于它们性能的信息。
8.可变与不可变 不可变对象有许多的优点,比如简单,安全等等。但是对于每一个不同的值都需要一个独立的对象,太多的对象可能会造成大量的垃圾回收。
当选择可变与不可变时应该有一个平衡。
一般的,可变对象用来避免产生大量的中间对象。一个典型的例子是连接大量的字符串。
如果你用一个不可变的字符串,你会产生很多需要进行垃圾回收的对象。这很浪费CPU的时间,使用可变对象是正确的解决方案(比如StringBuilder)。
String result="";
for(String s: arr){
result = result + s;
}
有时在某些情况下也是需要可变对象的,比如将可变对象作为参数传入方法,你不用使用很多语句便可以得到多个结果。
另外一个例子是排序和过滤:当然,你可以写一个方法来接收原始的集合,并且返回一个排好序的集合,但是那样对于大的集合就太浪费了。(来自StackOverFlow的dasblinkenlight’s的答案)
具体请看:Why String is Immutable?
9.父类与子类的构造函数 这个编译期错误的出现是父类默认的构造方法未定义,在java中,如果一个类没有定义构造方法,编译器会默认的为这个类添加一个无参的构造方法。如果在父类中定义了构造方法,在这个例子中是Super(String s),编译器就不会添加默认的无参构造方法,这就是上面这个父类的情形。
子类的构造器,不管是无参还有有参,都会调用父类的无参构造器。因为编译器试图在子类的两个构造方法中添加super()方法。但是父类默认的构造方法未定义,编译器就会报出这个错误信息。
想要修复这个问题,可以简单的通过1)在父类中添加一个Super()构造方法,像下面这样:
public Super(){
System.out.println("Super");
}
或者2)移除父类自定义的构造方法,或者3)在子类的构造方法中调用父类的super(value)方法。
具体请看:Constructor of Super and Stub
10.使用" "还是构造器 有两种方式可以创建字符串:
//1.使用字符串
String x = "abc";
//2.使用构造器
String y = new String("abc");
有什么区别?
下面的例子会给出一个快速的答案:
String a = "abc";
String b = "abc";
System.out.println(a==b);//true
System.out.println(a.equals(b));//true
String c = new String("abc");
String d = new String("abc");
System.out.println(a==b);//false
System.out.println(a.equals(b));//true
关于它们内存分配的更多信息,请参考Create Java String Using ” ” or Constructor?.
将来的工作
这个列表是我基于大量的github上的开源项目,Stack overflow上的问题,还有一些流行的google搜索的分析。没有明显示的评估证明它们是前10,但它们绝对是很常见的。如果您不同意任一部分,请留下您的评论。如果您能提出其它一些常见的错误,我将会非常感激。
原文链接: programcreek 翻译: ImportNew.com - 林林
译文链接:
http://www.importnew.com/12074.html
TestUser.java
import javax.xml.bind.annotation.XmlRootElement;
import org.codehaus.jackson.annotate.JsonProperty;
@XmlRootElement
public class TestUser {
/*@XmlElement(name="username")*/
@JsonProperty("username")
private String userName;
private String email;
public String getEmail() {
return email;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "TestUser [userName=" + userName + ", email=" + email + "]";
}
}
Test.java
import java.io.IOException;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Test {
private Logger logger = LoggerFactory.getLogger(Test.class);
/*private String getBaseUri()
{
return "http://192.168.1.223:8080/restfull-api";
}*/
@Test
public void testTest()
{
ObjectMapper mapper = new ObjectMapper();
/*AnnotationIntrospector introspector = new JaxbAnnotationIntrospector();
// make deserializer use JAXB annotations (only)
mapper.getDeserializationConfig().setAnnotationIntrospector(introspector);
// make serializer use JAXB annotations (only)
mapper.getSerializationConfig().setAnnotationIntrospector(introspector);*/
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
String userStr = "{\"username\":\"paul\",\"email\":\"paul@paul.com\"}";
try {
TypeReference<TestUser> temp = new TypeReference<TestUser>(){};
TestUser testUser = mapper.readValue(userStr, temp);
System.out.println(testUser.toString());
String result = mapper.writeValueAsString(testUser);
System.out.println(result);
} catch (JsonParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JsonMappingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Packt Publishing celebrates 10 years with a special $10 offer
It has been 10 years since Packt Publishing embarked on its mission to deliver effective learning and information services to IT professionals. In that time, it has published over 2000 titles and helped projects become household names, awarding over $400,000 through its Open Source Project Royalty Scheme.
To celebrate this huge milestone, Packt is offering all of its eBooks and Videos at just $10 each – this promotion covers every title and customers can stock up on as many copies as they like until July 5th.
If you’ve already tried a Packt title in the past, you’ll know this is a great opportunity to explore what’s new and maintain your personal and professional development. If you’re new to Packt, then now is the time to try their extensive range – Within their 2000+ titles range, you’ll find the knowledge you really need , whether that’s specific learning on an emerging technology or the key skills to keep you ahead of the competition in more established tech fields.’
More information is available at: http://bit.ly/1x4oR5r
angular-smarty 是一个基于 AngularJS 实现的自动完成的 UI 实现。
使用方法:
<html>
<head>
<title>angular-smarty demo</title>
<link rel="stylesheet" type="text/css" href="smarty.css"></link>
</head>
<body ng-controller="SmartyController">
<div class="container-main">
<h1>angular-smarty demo</h1>
<div class="container-autocomplete">
<input type="text" smarty-input select="setSelected(x)"
index="selected" list-items="suggestions" close="suggestionPicked()"
selection-made="selectionMade" ng-model="prefix"></input>
<div smarty-suggestions-box></div>
<input type="text" focus-me focus-when="{{selectionMade}}"></input>
</div>
</div>
</body>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.js"></script>
<script type="text/javascript" src="smarty-config.js"></script>
<script type="text/javascript" src="smarty.js"></script>
<script type="text/javascript">
$(function() {
angular.bootstrap(angular.element("body"), ["angular-smarty"]);
});
</script>
</html>
https://github.com/thumbtack/angular-smarty
在实践中我们发现对于大多数的应用领域,评估一个垃圾收集(GC)算法如何根据如下两个标准:
- 吞吐量越高算法越好
- 暂停时间越短算法越好
首先让我们来明确垃圾收集(GC)中的两个术语:吞吐量(throughput)和暂停时间(pause times)。 JVM在专门的线程(GC threads)中执行GC。 只要GC线程是活动的,它们将与应用程序线程(application threads)争用当前可用CPU的时钟周期。 简单点来说,吞吐量是指应用程序线程用时占程序总用时的比例。 例如,吞吐量99/100意味着100秒的程序执行时间应用程序线程运行了99秒, 而在这一时间段内GC线程只运行了1秒。
术语”暂停时间”是指一个时间段内应用程序线程让与GC线程执行而完全暂停。 例如,GC期间100毫秒的暂停时间意味着在这100毫秒期间内没有应用程序线程是活动的。 如果说一个正在运行的应用程序有100毫秒的“平均暂停时间”,那么就是说该应用程序所有的暂停时间平均长度为100毫秒。 同样,100毫秒的“最大暂停时间”是指该应用程序所有的暂停时间最大不超过100毫秒。
吞吐量 VS 暂停时间
高吞吐量最好因为这会让应用程序的最终用户感觉只有应用程序线程在做“生产性”工作。 直觉上,吞吐量越高程序运行越快。 低暂停时间最好因为从最终用户的角度来看不管是GC还是其他原因导致一个应用被挂起始终是不好的。 这取决于应用程序的类型,有时候甚至短暂的200毫秒暂停都可能打断终端用户体验。
因此,具有低的最大暂停时间是非常重要的,特别是对于一个交互式应用程序。
不幸的是”高吞吐量”和”低暂停时间”是一对相互竞争的目标(矛盾)。这样想想看,为了清晰起见简化一下:GC需要一定的前提条件以便安全地运行。 例如,必须保证应用程序线程在GC线程试图确定哪些对象仍然被引用和哪些没有被引用的时候不修改对象的状态。
为此,应用程序在GC期间必须停止(或者仅在GC的特定阶段,这取决于所使用的算法)。 然而这会增加额外的线程调度开销:直接开销是上下文切换,间接开销是因为缓存的影响。 加上JVM内部安全措施的开销,这意味着GC及随之而来的不可忽略的开销,将增加GC线程执行实际工作的时间。
因此我们可以通过尽可能少运行GC来最大化吞吐量,例如,只有在不可避免的时候进行GC,来节省所有与它相关的开销。
然而,仅仅偶尔运行GC意味着每当GC运行时将有许多工作要做,因为在此期间积累在堆中的对象数量很高。 单个GC需要花更多时间来完成, 从而导致更高的平均和最大暂停时间。 因此,考虑到低暂停时间,最好频繁地运行GC以便更快速地完成。 这反过来又增加了开销并导致吞吐量下降,我们又回到了起点。
综上所述,在设计(或使用)GC算法时,我们必须确定我们的目标:一个GC算法只可能针对两个目标之一(即只专注于最大吞吐量或最小暂停时间),或尝试找到一个二者的折衷。
HotSpot虚拟机上的垃圾收集
该系列的第五部分我们已经讨论过年轻代的垃圾收集器。 对于年老代,HotSpot虚拟机提供两类垃圾收集算法(除了新的G1垃圾收集算法),第一类算法试图最大限度地提高吞吐量,而第二类算法试图最小化暂停时间。 今天我们的重点是第一类,”面向吞吐量”的垃圾收集算法。
我们希望把重点放在JVM配置参数上,所以我只会简要概述HotSpot提供的面向吞吐量(throughput-oriented)垃圾收集算法。 当年老代中由于缺乏空间导致对象分配失败时会触发垃圾收集器(事实上,”分配”的通常是指从年轻代提升到年老代的对象)。
从所谓的”GC根”(GC roots)开始,搜索堆中的可达对象并将其标记为活着的,之后,垃圾收集器将活着的对象移到年老代的一块无碎片(non-fragmented)内存块中,并标记剩余的内存空间是空闲的。 也就是说,我们不像复制策略那样移到一个不同的堆区域,像年轻代垃圾收集算法所做的那样。
相反地,我们把所有的对象放在一个堆区域中,从而对该堆区域进行碎片整理。 垃圾收集器使用一个或多个线程来执行垃圾收集。 当使用多个线程时,算法的不同步骤被分解,使得每个收集线程大多时候工作在自己的区域而不干扰其他线程。 在垃圾收集期间,所有的应用程序线程暂停,只有垃圾收集完成之后才会重新开始。
现在让我们来看看跟面向吞吐量垃圾收集算法有关的重要JVM配置参数。
-XX:+UseSerialGC
我们使用该标志来激活串行垃圾收集器,例如单线程面向吞吐量垃圾收集器。 无论年轻代还是年老代都将只有一个线程执行垃圾收集。 该标志被推荐用于只有单个可用处理器核心的JVM。 在这种情况下,使用多个垃圾收集线程甚至会适得其反,因为这些线程将争用CPU资源,造成同步开销,却从未真正并行运行。
-XX:+UseParallelGC
有了这个标志,我们告诉JVM使用多线程并行执行年轻代垃圾收集。 在我看来,Java 6中不应该使用该标志因为-XX:+UseParallelOldGC显然更合适。 需要注意的是Java 7中该情况改变了一点(详见本概述),就是-XX:+UseParallelGC能达到-XX:+UseParallelOldGC一样的效果。
-XX:+UseParallelOldGC
该标志的命名有点不巧,因为”老”听起来像”过时”。 然而,”老”实际上是指年老代,这也解释了为什么-XX:+UseParallelOldGC要优于-XX:+UseParallelGC:除了激活年轻代并行垃圾收集,也激活了年老代并行垃圾收集。 当期望高吞吐量,并且JVM有两个或更多可用处理器核心时,我建议使用该标志。
作为旁注,HotSpot的并行面向吞吐量垃圾收集算法通常称为”吞吐量收集器”,因为它们旨在通过并行执行来提高吞吐量。
-XX:ParallelGCThreads
通过-XX:ParallelGCThreads=<value>我们可以指定并行垃圾收集的线程数量。 例如,-XX:ParallelGCThreads=6表示每次并行垃圾收集将有6个线程执行。 如果不明确设置该标志,虚拟机将使用基于可用(虚拟)处理器数量计算的默认值。 决定因素是由Java Runtime。availableProcessors()方法的返回值N,如果N<=8,并行垃圾收集器将使用N个垃圾收集线程,如果N>8个可用处理器,垃圾收集线程数量应为3+5N/8。
当JVM独占地使用系统和处理器时使用默认设置更有意义。 但是,如果有多个JVM(或其他耗CPU的系统)在同一台机器上运行,我们应该使用-XX:ParallelGCThreads来减少垃圾收集线程数到一个适当的值。 例如,如果4个以服务器方式运行的JVM同时跑在在一个具有16核处理器的机器上,设置-XX:ParallelGCThreads=4是明智的,它能使不同JVM的垃圾收集器不会相互干扰。
-XX:-UseAdaptiveSizePolicy
吞吐量垃圾收集器提供了一个有趣的(但常见,至少在现代JVM上)机制以提高垃圾收集配置的用户友好性。 这种机制被看做是HotSpot在Java 5中引入的”人体工程学”概念的一部分。 通过人体工程学,垃圾收集器能将堆大小动态变动像GC设置一样应用到不同的堆区域,只要有证据表明这些变动将能提高GC性能。 “提高GC性能”的确切含义可以由用户通过-XX:GCTimeRatio和-XX:MaxGCPauseMillis(见下文)标记来指定。
重要的是要知道人体工程学是默认激活的。 这很好,因为自适应行为是JVM最大优势之一。 不过,有时我们需要非常清楚对于特定应用什么样的设置是最合适的,在这些情况下,我们可能不希望JVM混乱我们的设置。 每当我们发现处于这种情况时,我们可以考虑通过-XX:-UseAdaptiveSizePolicy停用一些人体工程学。
-XX:GCTimeRatio
通过-XX:GCTimeRatio=<value>我们告诉JVM吞吐量要达到的目标值。 更准确地说,-XX:GCTimeRatio=N指定目标应用程序线程的执行时间(与总的程序执行时间)达到N/(N+1)的目标比值。 例如,通过-XX:GCTimeRatio=9我们要求应用程序线程在整个执行时间中至少9/10是活动的(因此,GC线程占用其余1/10)。 基于运行时的测量,JVM将会尝试修改堆和GC设置以期达到目标吞吐量。 -XX:GCTimeRatio的默认值是99,也就是说,应用程序线程应该运行至少99%的总执行时间。
-XX:MaxGCPauseMillis
通过-XX:GCTimeRatio=<value>告诉JVM最大暂停时间的目标值(以毫秒为单位)。 在运行时,吞吐量收集器计算在暂停期间观察到的统计数据(加权平均和标准偏差)。 如果统计表明正在经历的暂停其时间存在超过目标值的风险时,JVM会修改堆和GC设置以降低它们。 需要注意的是,年轻代和年老代垃圾收集的统计数据是分开计算的,还要注意,默认情况下,最大暂停时间没有被设置。
如果最大暂停时间和最小吞吐量同时设置了目标值,实现最大暂停时间目标具有更高的优先级。 当然,无法保证JVM将一定能达到任一目标,即使它会努力去做。 最后,一切都取决于手头应用程序的行为。
当设置最大暂停时间目标时,我们应注意不要选择太小的值。 正如我们现在所知道的,为了保持低暂停时间,JVM需要增加GC次数,那样可能会严重影响可达到的吞吐量。 这就是为什么对于要求低暂停时间作为主要目标的应用程序(大多数是Web应用程序),我会建议不要使用吞吐量收集器,而是选择CMS收集器。 CMS收集器是本系列下一部分的主题。