锁定老帖子 主题:看高手代码--从小case学大道理
该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2011-03-22
看到这个帖子,自己也写了一个测试例子,但是结果好像不一样,是不是我的例子写的有问题吗?
import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class TestGetMessage { private static final String STATUS_305 = "Use Proxy"; private static final String STATUS_307 = "Temporary Redirect"; private static final String STATUS_400 = "Bad Request"; private static final String STATUS_401 = "Unauthorized"; private static final String STATUS_402 = "Payment Required"; private static final String STATUS_403 = "Forbidden"; private static final String STATUS_404 = "Not Found"; private static final String STATUS_405 = "Method Not Allowed"; private static final String STATUS_406 = "Not Acceptable"; private static final String STATUS_407 = "Proxy Authentication Required"; private static final String STATUS_408 = "Request Timeout"; static Map<String, String> httpStatusCodeMappings = new ConcurrentHashMap<String, String>(); static { httpStatusCodeMappings.put("sc.305", STATUS_305); httpStatusCodeMappings.put("sc.307", STATUS_307); httpStatusCodeMappings.put("sc.400", STATUS_400); httpStatusCodeMappings.put("sc.401", STATUS_401); httpStatusCodeMappings.put("sc.402", STATUS_402); httpStatusCodeMappings.put("sc.403", STATUS_403); httpStatusCodeMappings.put("sc.404", STATUS_404); httpStatusCodeMappings.put("sc.405", STATUS_405); httpStatusCodeMappings.put("sc.406", STATUS_406); httpStatusCodeMappings.put("sc.407", STATUS_407); httpStatusCodeMappings.put("sc.408", STATUS_408); } public static String getSwitchMessage(int status){ switch (status) { case 305: return STATUS_305; case 404: return STATUS_404; } return null; } public static String getMapMessage(int status){ return httpStatusCodeMappings.get("sc."+ status); } public static void main(String[] args) { int status = 404; long loopNum = 100000000L; long switchStartTime = System.currentTimeMillis(); for(long i = 0; i < loopNum; i++){ getSwitchMessage(status); } System.out.println("switch:"+(System.currentTimeMillis() - switchStartTime)); long mapStartTime = System.currentTimeMillis(); for(long i = 0; i < loopNum; i++){ getSwitchMessage(status); } System.out.println("map:"+(System.currentTimeMillis() - mapStartTime)); } } |
|
返回顶楼 | |
发表时间:2011-03-22
lubezhang 写道 看到这个帖子,自己也写了一个测试例子,但是结果好像不一样,是不是我的例子写的有问题吗?
import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class TestGetMessage { private static final String STATUS_305 = "Use Proxy"; private static final String STATUS_307 = "Temporary Redirect"; private static final String STATUS_400 = "Bad Request"; private static final String STATUS_401 = "Unauthorized"; private static final String STATUS_402 = "Payment Required"; private static final String STATUS_403 = "Forbidden"; private static final String STATUS_404 = "Not Found"; private static final String STATUS_405 = "Method Not Allowed"; private static final String STATUS_406 = "Not Acceptable"; private static final String STATUS_407 = "Proxy Authentication Required"; private static final String STATUS_408 = "Request Timeout"; static Map<String, String> httpStatusCodeMappings = new ConcurrentHashMap<String, String>(); static { httpStatusCodeMappings.put("sc.305", STATUS_305); httpStatusCodeMappings.put("sc.307", STATUS_307); httpStatusCodeMappings.put("sc.400", STATUS_400); httpStatusCodeMappings.put("sc.401", STATUS_401); httpStatusCodeMappings.put("sc.402", STATUS_402); httpStatusCodeMappings.put("sc.403", STATUS_403); httpStatusCodeMappings.put("sc.404", STATUS_404); httpStatusCodeMappings.put("sc.405", STATUS_405); httpStatusCodeMappings.put("sc.406", STATUS_406); httpStatusCodeMappings.put("sc.407", STATUS_407); httpStatusCodeMappings.put("sc.408", STATUS_408); } public static String getSwitchMessage(int status){ switch (status) { case 305: return STATUS_305; case 404: return STATUS_404; } return null; } public static String getMapMessage(int status){ return httpStatusCodeMappings.get("sc."+ status); } public static void main(String[] args) { int status = 404; long loopNum = 100000000L; long switchStartTime = System.currentTimeMillis(); for(long i = 0; i < loopNum; i++){ getSwitchMessage(status); } System.out.println("switch:"+(System.currentTimeMillis() - switchStartTime)); long mapStartTime = System.currentTimeMillis(); for(long i = 0; i < loopNum; i++){ getSwitchMessage(status); } System.out.println("map:"+(System.currentTimeMillis() - mapStartTime)); } } 第二个for循环怎么还getSwitchMessage(status);??应该是 getMapMessage(int status)了吧 |
|
返回顶楼 | |
发表时间:2011-03-22
徐风子 写道 skydream 写道 sw1982 写道 ...lookup 一下hashmap真的那么低效吗? 建议复习下数据结构哦,你这些总结是没错,可是很表面
典型的没有写过高并发程序的思维方式,明明可以节约的地方,仅仅几行代码就可以优化,偏偏不做。 hashmap再快,也比case 一个 整型满上1w倍。 性能,是一点一点挤牙膏挤出来的,哪能到处浪费啊。 首先,谁说hash表比case慢一万倍的?? 其实case的代码实现是 if ..else if形式的,复杂度是O(n) hashMap 的复杂度是 O(1),当然里面的实现有函数调用,(函数调用的效率我没测试过,不过据《代码大全2》里面的资料,java的函数调用所消耗的时间和 普通赋值语句相同。) 就是说hashMap实际操作时间不过 十几个 语句周期。 代码最大的问题是 明明是一堆静态常量,为什么要用 ConcurrentHashMap?? 感觉实际编码的过程是: 开始不知道为什么使用了一个大而全,含义复杂的map,(所以做成同步,key中出现了字符串拼装),后来发现效率不够,于是打补丁,就出现了那堆case。 没什么好说的,不过是一堆临时代码,真正应该做的是重构应该重新定义Map的结构。 其实这种东西效率最高的是 以空间换时间: String[] httpStatusCode = new int[600]; httpStatusCode[404] = "Not Found"; ……………… 只是多使用了 600 * 8 = 4.8k空间。 或者最普通的方式,使用: com.google.common.collect.ImmutableMap 方法是好方法,但case的代码实现是 if ..else 是错误的,深入理解计算机系统里面有明确解释,case背后的代码和ifelse比是数量级的差别尤其在case部分的数值是连续的情况下,和hashmap的差距应该至少可以达到两个数量级 正好最近讨论一个帖子,map的存取已经成为瓶颈 楼上你是代码有问题,实际结果: switch:4334 map:117842 这个差距实际被return string带来的开销抹平不少, public static int getSwitchMessage(int status){ switch (status) { case 305: return 1; case 404: return 2; } return 0; } public static int getMapMessage(int status){ httpStatusCodeMappings.get("sc."+ status); return 0; } 这个开销是: switch:1399 map:108843 遇到桶内元素大于1,应该还能拉个把数量级 |
|
返回顶楼 | |
发表时间:2011-03-22
myumen 写道 抛出异常的爱 写道 pengzhoushuo 写道 好贴,程序员都应该学习。
1、认为HashMap性能比switch高的同学建议学习下数据结构,所谓HashMap就是一个链表散列,一个连续的链表用于保存key,默认的情况下它的长度是16。HashMap对Key做Hash,根据取到的Hash码再找到对应的的key所在的散,再通过查找所在散列里对应Key从而找到Value。这种速度比得上4个case的switch? 2、以可读性作为借口的童鞋们的理由是站不住脚的,加了一个switch就看不懂了?即使是,过错也不在写程序的人,而是读程序的人,注释是写得清清楚楚...... 3、说写好代码不如加硬件的童鞋,你觉得自己比不上机器?加硬件那是无耐之举。比如你做了一个OA管理系统,你跟领导说你需要10台高性能的机器才能跑起来,领导会怎么看你?可别跟我说什么云计算。最后套用达文西的话,做人要有良知才行啊,写程序也一样,要对得起自己良心。 天地良心. 把代码写好懂点才更对的点别人 少作孽写一堆别人看不懂的代码 哥们,虽然你有5颗星,但这次不得不反对你了。个人觉得:这是一个非常不错的Tips,不至于看不懂吧?我写的话肯定会在switch语句块前注明为什么要这样写。考虑另外一个问题: List someList = new ArrayList(); try { someList = someObject.somdMethod(); // more } catch (Exception e) { // do sth } return someList; new ArrayList()就是没有必要的,当然啦,也不会太影响性能的,也不会产生可读性的问题,但是这样写真的应该吗?作为程序员,本身就应该精益求精,如果实际中我写了我粘上的这种类似的代码,我感到羞愧,不为别的,因为我想做到更好。 在讨论可读性和性能的问题,你这个例子说明了什么,可读性差,性能差,什么都不能说明 lz的代码可读性还可以,一般都会真么做的。 我一直认为可读性大于性能,当然这有个范围。 |
|
返回顶楼 | |
发表时间:2011-03-22
lubezhang 写道 看到这个帖子,自己也写了一个测试例子,但是结果好像不一样,是不是我的例子写的有问题吗?
import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class TestGetMessage { private static final String STATUS_305 = "Use Proxy"; private static final String STATUS_307 = "Temporary Redirect"; private static final String STATUS_400 = "Bad Request"; private static final String STATUS_401 = "Unauthorized"; private static final String STATUS_402 = "Payment Required"; private static final String STATUS_403 = "Forbidden"; private static final String STATUS_404 = "Not Found"; private static final String STATUS_405 = "Method Not Allowed"; private static final String STATUS_406 = "Not Acceptable"; private static final String STATUS_407 = "Proxy Authentication Required"; private static final String STATUS_408 = "Request Timeout"; static Map<String, String> httpStatusCodeMappings = new ConcurrentHashMap<String, String>(); static { httpStatusCodeMappings.put("sc.305", STATUS_305); httpStatusCodeMappings.put("sc.307", STATUS_307); httpStatusCodeMappings.put("sc.400", STATUS_400); httpStatusCodeMappings.put("sc.401", STATUS_401); httpStatusCodeMappings.put("sc.402", STATUS_402); httpStatusCodeMappings.put("sc.403", STATUS_403); httpStatusCodeMappings.put("sc.404", STATUS_404); httpStatusCodeMappings.put("sc.405", STATUS_405); httpStatusCodeMappings.put("sc.406", STATUS_406); httpStatusCodeMappings.put("sc.407", STATUS_407); httpStatusCodeMappings.put("sc.408", STATUS_408); } public static String getSwitchMessage(int status){ switch (status) { case 305: return STATUS_305; case 404: return STATUS_404; } return null; } public static String getMapMessage(int status){ return httpStatusCodeMappings.get("sc."+ status); } public static void main(String[] args) { int status = 404; long loopNum = 100000000L; long switchStartTime = System.currentTimeMillis(); for(long i = 0; i < loopNum; i++){ getSwitchMessage(status); } System.out.println("switch:"+(System.currentTimeMillis() - switchStartTime)); long mapStartTime = System.currentTimeMillis(); for(long i = 0; i < loopNum; i++){ getSwitchMessage(status); } System.out.println("map:"+(System.currentTimeMillis() - mapStartTime)); } } 错误就不说了,你这样测试时没有意义的 |
|
返回顶楼 | |