您的位置:首页 > 编程语言

神奇的代码-常见错误代码注意点

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 神奇 错误