神奇的代码-常见错误代码注意点
2018-05-17 11:19
267 查看
import java.math.BigDecimal; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; import org.junit.Test; /** * 常见错误代码注意点 * @author Yuanqy * @time 2015年5月10日 9:23:00 */ public class ExceptionTest { /** * 用例1:入箱与拆箱 <br> * Integer、Short、Byte、Character、Long这几个包装类的valueOf方法的实现是类似的:会有缓存cache.high,cache.low;<br> * Double、Float的valueOf方法的实现是类似的:要么直接赋值,要么通过String转。 <br> * Boolean的valueOf方法的实现是个三目运算,形如` return (b ? TRUE : FALSE); */ @Test public void test1() { System.out.println("==test1======================================="); // //JDK,源代码: // public static Integer valueOf(int i) { // assert IntegerCache.high >= 127; // if (i >= IntegerCache.low && i <= IntegerCache.high) // return IntegerCache.cache[i + (-IntegerCache.low)]; // return new Integer(i); // } Integer i1 = 128; Integer i2 = 128; Integer i3 = 127; Integer i4 = 127; System.out.println("i1 == i2:" + (i1 == i2));// false System.out.println("i3 == i4:" + (i3 == i4));// true } /** * 用例2:入箱与拆箱 <br> * 在java代码中,很多场景会用到装箱和拆箱操作,稍不留神,就会掉坑里。<br> * 保证不出异常,就在运算过程中用同种类型。装箱就全部装箱。不装箱就全部不装箱。 */ @Test public void test2() { class TestBean { private Integer test; public Integer getTest() { return test; } public void setTest(Integer test) { this.test = test; } } try { System.out.println("==test2======================================="); TestBean bean = new TestBean(); bean.setTest(bean != null ? bean.getTest() : new Integer(1)); // 这行正常 bean.setTest(bean != null ? bean.getTest() : 1);// 这行异常【很经典的异常】,原因是三元表达式的执行过程和 int/Integer 的入箱与拆箱 过程照成的。 } catch (Exception e) { e.printStackTrace(); throw e; } } /** * 用例3:注意数据溢出 */ @Test public void test3() { System.out.println("==test3======================================="); int s = 1; for (int i = 10; i <= 49; i++) { s = s * i; System.out.println(s + "==" + Integer.toBinaryString(s)); } System.out.println("结果是:" + s);// 结果是:0 } /** * 用例4:不要相信 get/Select,要保证操作原子性 * 并且:基本数据类型的 ++ ,-- 运算符 也非线程安全,是非原子性的。 * 计数操作,使用AtomicXX类操作 * 还有:Thread、Runnable、Callable、Future、FutureTask,这些多线程操作都有线程安全问题,需要特殊处理。 * 【网上误人子弟的真JB多,特别是IO,多线程的文章】。 * @throws InterruptedException */ @Test public void test4() throws InterruptedException { System.out.println("==test4======================================="); int sum = 100; final CountDownLatch latch = new CountDownLatch(sum); Thread t = new Thread() { private AtomicInteger count = new AtomicInteger(0);// 计数不能使用int做++count private BigDecimal money = BigDecimal.ZERO; public BigDecimal getMoney() { return money; } public void setMoney(BigDecimal money) { this.money = money; } @Override public void run() { BigDecimal curM = BigDecimal.ZERO; // synchronized (curM) {//加同步块或读写锁 try { curM = getMoney(); curM = curM.add(BigDecimal.ONE); setMoney(curM); System.out.println(count.addAndGet(1) + ":getMoney=" + getMoney().toPlainString()); latch.countDown(); } catch (Exception e) { e.printStackTrace(); } // } } }; // t只实例一次 for (int i = 0; i < sum; i++) { new Thread(t).start(); } latch.await(); System.out.println("结果:执行了100次加操作,结果却不是100。"); } /** * 用例5:涉及到小数操作,不允许出现float double浮点数类型 * 特别是金融场景 */ @Test public void test5() { System.out.println("==test5======================================="); System.out.println(0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1); System.out.println(0.1 * 10); } /** * 浮点数操作,最好使用BigDecimal 或 String */ @Test public void test6() { System.out.println("==test6======================================="); Double d=123456789.98D; System.out.println(new BigDecimal(d).toString());// 错 System.out.println(new Double(d).toString());// 错 System.out.println(new BigDecimal(new Double(d).toString()).toString());// 对 System.out.println(new BigDecimal(d).toPlainString());// 错 } /** * 代码都是假随机。 * 可以预测的,甚至可以输出想要的字符。 */ @Test public void test7() { System.out.println("==test7======================================="); class RandomBuild { public String getStr(long seed) { Random ran = new Random(seed); StringBuilder sb = new StringBuilder(); while (true) { int k = ran.nextInt(27); System.out.println("char:" + k + ",number:" + k); if (k == 0) break; k += 96; sb.append((char) k); } return sb.toString(); } } RandomBuild rb = new RandomBuild(); System.out.println(rb.getStr(-229985452) + " " + rb.getStr(-147909649)); } }
执行结果控制台:
==test1======================================= i1 == i2:false i3 == i4:true ==test2======================================= java.lang.NullPointerException at ExceptionTest.test2(ExceptionTest.java:60) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) at org.junit.runners.ParentRunner.run(ParentRunner.java:309) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) ==test3======================================= 10==1010 110==1101110 1320==10100101000 17160==100001100001000 240240==111010101001110000 3603600==1101101111110010010000 57657600==11011011111100100100000000 980179200==111010011011000101100100000000 463356416==11011100111100100001000000000 213837312==1100101111101110011000000000 -18221056==11111110111010011111100000000000 -382642176==11101001001100010101100000000000 171806720==1010001111011001000000000000 -343412736==11101011100001111111000000000000 348028928==10100101111101000000000000000 110788608==110100110101000000000000000 -1414463488==10101011101100010000000000000000 464191488==11011101010110000000000000000 112459776==110101101000000000000000000 -1033633792==11000010011001000000000000000000 -944242688==11000111101110000000000000000000 793247744==101111010010000000000000000000 -385875968==11101001000000000000000000000000 150994944==1001000000000000000000000000 838860800==110010000000000000000000000000 -704643072==11010110000000000000000000000000 402653184==11000000000000000000000000000 2013265920==1111000000000000000000000000000 -805306368==11010000000000000000000000000000 -1342177280==10110000000000000000000000000000 -2147483648==10000000000000000000000000000000 -2147483648==10000000000000000000000000000000 0==0 0==0 0==0 0==0 0==0 0==0 0==0 0==0 结果是:0 ==test4======================================= 1:getMoney=1 2:getMoney=2 3:getMoney=3 4:getMoney=4 5:getMoney=5 6:getMoney=6 7:getMoney=7 8:getMoney=8 9:getMoney=9 10:getMoney=10 11:getMoney=11 12:getMoney=12 13:getMoney=13 14:getMoney=14 15:getMoney=15 16:getMoney=16 17:getMoney=17 18:getMoney=18 19:getMoney=19 20:getMoney=20 21:getMoney=21 22:getMoney=22 23:getMoney=22 24:getMoney=23 25:getMoney=24 26:getMoney=25 27:getMoney=26 28:getMoney=27 29:getMoney=28 30:getMoney=29 31:getMoney=30 32:getMoney=31 33:getMoney=32 34:getMoney=32 35:getMoney=33 36:getMoney=33 37:getMoney=34 38:getMoney=35 39:getMoney=36 40:getMoney=37 41:getMoney=38 42:getMoney=39 44:getMoney=39 43:getMoney=38 47:getMoney=42 49:getMoney=44 46:getMoney=41 51:getMoney=46 53:getMoney=48 45:getMoney=40 54:getMoney=49 57:getMoney=52 55:getMoney=50 60:getMoney=55 61:getMoney=56 62:getMoney=57 52:getMoney=47 50:getMoney=45 64:getMoney=59 48:getMoney=43 67:getMoney=61 68:getMoney=62 69:getMoney=63 71:getMoney=65 66:getMoney=60 72:getMoney=66 74:getMoney=68 65:getMoney=59 75:getMoney=69 76:getMoney=70 77:getMoney=71 63:getMoney=58 79:getMoney=73 80:getMoney=74 59:getMoney=54 81:getMoney=75 82:getMoney=76 58:getMoney=53 84:getMoney=78 85:getMoney=79 56:getMoney=51 83:getMoney=77 78:getMoney=72 89:getMoney=83 73:getMoney=67 91:getMoney=84 70:getMoney=64 99:getMoney=85 98:getMoney=90 96:getMoney=89 97:getMoney=89 95:getMoney=87 94:getMoney=86 100:getMoney=85 93:getMoney=85 92:getMoney=85 90:getMoney=83 88:getMoney=82 87:getMoney=81 86:getMoney=80 结果:执行了100次加操作,结果却不是100。 ==test5======================================= 0.9999999999999999 1.0 ==test6======================================= 123456789.98000000417232513427734375 1.2345678998E8 123456789.98 123456789.98000000417232513427734375 ==test7======================================= char:8,number:8 char:5,number:5 char:12,number:12 char:12,number:12 char:15,number:15 char:0,number:0 char:23,number:23 char:15,number:15 char:18,number:18 char:12,number:12 char:4,number:4 char:0,number:0 hello world
相关文章推荐
- Go的50坑:新Golang开发者要注意的陷阱、技巧和常见错误[2]
- 常见iPhone错误代码提示及解决方法
- 常见网络错误代码
- 一个超复杂的间接递归——C语言初学者代码中的常见错误与瑕疵(6)
- ITV常见故障错误代码(中兴平台)
- C语言初学者代码中的常见错误与瑕疵(22)
- symbian 开发常见错误代码及原因总结
- JSP中常见TOMCAT错误代码原因
- 常见 HTTP/FTP/WebSocket 错误代码大全
- C语言初学者代码中的常见错误与瑕疵(21)
- 运维注意事项以及常见错误解决办法
- HTTP常见错误代码
- mybatis常见错误及注意事项
- ORACLE常见错误代码的分析与解决(一)
- ORACLE常见错误代码的分析与解决(一)
- Xcode 常见错误代码及解决方案
- Oracle常见错误代码
- [常见错误]Tomcat找不到符号链接过去的代码
- golang新手应注意的几个常见错误
- C语言初学者代码中的常见错误与瑕疵(18)