常见问题 | 错误形式 | 正确表达说明 |
结果不精确 | System.out.println(0.1 + 0.2 - 0.3 == 0); 输出不是true。 | double类型数据不一定能够精确表示,尽量使用int或long型数据做数值运算。一定要用double类型时务必要注意可能存在的误差。 需要判断一个数(例如二次方程判断式)是否为0,可以判断其绝对值是否小于一个充分小的数: double a = 0.1 + 0.2 – 0.3; double zero = 1e-6; Boolean isZero = Math.abs(a) < zero; |
漏掉后缀 | float f = 3.14; 有编译错误。 | 浮点数常量默认为double类型。不得已需要将浮点数其表示为float型时应加后缀F: float f = 3.14F; float类型数据不够精确,使用还麻烦,不必为了节约四个字节内存牺牲精确性,强烈不推荐使用。 |
字符和字符串混淆 | char c = 'ab'; 编译错误。 | 字符型变量只能存储单个字符,字符型常量写在一对单引号''内。需要存储多个字符时需要使用字符串类型String变量,字符串常量写在一对双引号""内: String s = "ab"; |
忘记使用转义字符 | char c = '''; 编译错误。 | 特殊字符(单引号',双引号",反斜线,回车,制表位等)必须使用转义字符方式书写: char c = '''; |
没有做字符串连接 | System.out.println('A' + 'B'); 输出的结果并不是AB。 System.out.println('A' + 1); 输出的结果不是B也不是A1。 | 用加号+做字符串连接的条件是左右两侧至少有一个是字符串,否则做数值加法。 解决办法是将其中一个变为字符串,或先与空字符串""连接生成字符串。以下语句都输出AB: System.out.println("A" + 'B'); System.out.println("" + 'A' + 'B');//万能办法 |
变量反复定义 | int a = 1; double a = 2; 编译错误。 | 变量必须先声明,再赋值,后使用,并且在其作用域内只能被声明一次,声明后类型固定不变。 |
变量装不下数据 | int a = 3.14; 编译错误。 | 变量只能装下与其表示范围一致或更小的数据。double类型的表示范围远远大于int的表示范围,此处需要用强制类型转换,小数部分被截断。 int a = (int)(3.14); 定义变量时务必考虑要存储数据的范围,例如手机号不能用int型而要用long型存储;身份证号不能用long型而要用String型存储。 |
int a = Math.sqrt(4); 4的平方根是2,但编译错误。 | Math类中的方法返回值都是double类型数据。错误原因同上。 |
boolean a = 1; int b = (int)("123"); 编译错误。 | Java语言中boolean和String类型数据都不是数值,无法和数值进行双向自动或强制类型转换。 |
交换变量失败 | a = b; b = a; | 交换变量一般需要通过临时变量,否则a中数值会被覆盖而丢失: temp = a; a = b; b = temp; |
结果不是字符而是数值 | System.out.println('A' + 1); 不输出B。 | 由于自动类型转换,char型数据做数值运算会被提升为int型以上,想要将结果作为一个Unicode转换回字符,需要强制类型转换: System.out.println((char)('A' + 1)); |
乘号被省略 | int a = 1, b = 2, c = ab, d = 3(a + b); 编译错误。 | 乘号不可以被省略,此处ab是与a和b都不同的变量,3(也是不能被理解的表达式。 int a = 1, b = 2, c = a * b, d = 3 * (a + b); |
结果因整数除法错误 | double r = 1, h = 1; double v = 1 / 3 * Math.PI * r * r * h; 计算圆锥体积,但v的结果为0。 int n = 5; double a = 6; double b = Math.pow(a, 1 / n); 求a的n次方根结果总是1。 | 当除号/两侧都是整数时,执行的是整数除法,结果是数学结果的整数部分,小数部分被丢弃。想要精确结果,至少将被除数或除数之一转换为double类型: 1.0 / 3 * Math.PI * r * r * h 1 / 3.0 * Math.PI * r * r * h 1.0 / 3.0 * Math.PI * r * r * h (double)(1) / 3 * Math.PI * r * r * h …… Math.pow(a, 1 / (double)(n)) |
乘方书写错误 | a^n | 运算符^在Java语言中并不表示乘方,计算a的n次方需要使用方法Math.pow(a,n)。 |
结果因优先级错误 | 要生成0到n的随机整数,但(int)Math.random() * n得到的总是0。 | 单目运算符的优先级比算术运算符高,Math.random()生成的是介于0和1之间的纯小数,经过强制类型转换为int后结果总是0。 不要背优先级,将需要先计算的部分放入括号中保证优先级:(int)(Math.random() * n)。 |
==和=混淆 | System.out.println(1 = 2); 编译错误。 | =为赋值运算符,左侧必须是变量(左值),表达式结果是左侧变量的值;==为比较运算符,结果为boolean值,true或false。 |
双边不等式 | int a = 1, b = 2, c = 3; System.out.println(a > b > c); 编译错误。 | 比较运算符的结果都是boolean值,true或false,不能再和数值作比较运算,双边不等式务必使用逻辑运算符连接:(a > b) && (b > c)。 |
闰年的判断 | 忘记是否整除400和100的条件,结果3000年被误判为闰年。 | 判断一个年份n是否为闰年的正确表达式: (n % 400 == 0) || ((n % 100 != 0) && (n % 4 == 0)) |
滥用++和-- | i+++i+i+++i | ++和—一定单独使用,不要和其他运算符混合在一起,否则代码可读性太差。 |
输入数据错误 | Scanner类没导入就定义对象,编译错误。 Scanner input = new Scanner(System.in); | Scanner类在使用前必须导入,import语句写在package语句后,类定义之前。 import java.util.Scanner; |
int i = input.nextDouble(); 编译错误。 | 等号右侧读取double类型数据,左侧却是int型变量,需改为input.nextInt(),或进行强制类型转换。 |
int i = input.nextInt(); 用户输入3.14,运行时异常。 | nextInt()方法读取int型数据,用户输入double类型数据,类型不匹配,用户只能输入int型数据,或将语句改为以下以读取double型数据: double d = intput.nextDouble(); |
char c = input.nextChar(); 编译错误。 | Scanner类型对象没有nextChar()方法,读取单个字符需要先读整个字符串,再取首个字符: char c = input.nextLine().charAt(0); |
int age = input.nextInt(); String name = input.nextLine(); double height = input.nextDouble(); 用户输入:20 回车 Tom 回车 1.8 回车 程序运行时异常。事实上,用户没有机会输入1.8即已产生异常。 | nextInt()、nextDouble()和next()的特点:从非空字符(空格、回车、制表位等)开始读取,直到空字符结束,空字符留在输入流中。 nextLine()的特点:从任意字符开始读取,直到回车结束,回车被从输入流中取出并丢弃。 nextInt()读取20后,回车还在输入流中,残留的回车被nextLine()读取到,当做字符串结束,所以name是个空字符串"",字符串Tom被nextDouble()读取引发异常。 临时解决方法1:将nextLine()替换为next()忽略残留回车 String name = scan.next(); next()会跳过20后的回车,从非空字符开始读取,读到Tom后的回车结束,nextDouble()也会跳过Tom后的回车,读到1.8。 临时解决方案2:调换nextInt()和nextLine()的顺序,先读字符串name,再读数值age,避免读数值age后的回车残留干扰。 临时解决方案3:在读取数值age之后,读取字符串name之前加语句input.nextLine();读取并丢弃读数值age后残留的回车。 更好的解决方案将在学习包装类后介绍。 |
中文乱码 | 程序正确,但输出中文乱码 | Java没有正确解码操作系统读取并编码的中文字符。 如果是用Netbeans编程,右键单击项目-属性-编码,改为GB18030。 |