java math.random()返回值范围-(知识点)引号内存牺牲精确性的常见问题错误形式
常见问题
错误形式
正确表达说明
结果不精确
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 = ''';
编译错误。
特殊字符(单引号',双引号",反斜线\,回车java math.random()返回值范围,制表位等)必须使用转义字符方式书写:
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;
编译错误。
变量必须先声明java math.random()返回值范围,再赋值,后使用,并且在其作用域内只能被声明一次,声明后类型固定不变。
变量装不下数据
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。