最近项目中将double类型数据转 int类型时竟然发生了精度丢失,查了好几个资料才明白原因,这不禁让我想写一个Java中几种主要用的基本类型int、double、float、String的相互转化的一些方法并解释产生问题的原因,最后还补充了一个不常用的类型BigDecimal,以此记录。
int转所有类型:
//int转所有类型
public static void intCastAll(int i,double db,float fl,String str){
//int转double
i = -123;
//方法一:隐式转换,由于double的范围和内存都比int大,因此int转double是隐式的,无需类型转换
db = i;
System.out.println("int转double的第一种方法:"+db);
//方法二:使用Double.valueOf()方法
double db2 = Double.valueOf(i);
System.out.println("int转double的第二种方法:"+db2);
//int转float
//考虑到有的时候给的是Integer类型
// 方法一:可以先将Integer转int再转float
Integer itg = new Integer(20);
int i2 = itg.intValue();
fl = (float)i2;
System.out.println("int转float的第一种方法:"+fl);
//方法二:可以先将Integer转String再转float
str = String.valueOf(i);
float fl2 = Float.valueOf(str);
System.out.println("int转float的第一种方法:"+fl2);
//int转str
//方法一:添加""
str = i+"";
System.out.println("int转String的第一种方法:"+str);
//方法二:使用String.valueOf()方法
String str2 = String.valueOf(i);
System.out.println("int转String的第二种方法:"+str2);
//方法三:使用Integer.toString()方法
String str3 = Integer.toString(i);
System.out.println("int转String的第三种方法:"+str3);
}
double转所有类型:
//double转所有类型
public static void doubleCastAll(int i,double db,float fl,String str){
//double转int
db = 1.25;
double db2 = 2.3*100;
//方法一:强制转化,大部分情况下是没有问题的,但是遇到一些情况会出现精度丢失
i = new Double(db).intValue();
System.out.println("double转int的第一种方法:"+i);
int i2 = new Double(db2).intValue();
System.out.println("精度丢失示例:"+i2);
//方法二:使用DecimalFormat,转换后得到的是String类型需要再转为int类型
str = new DecimalFormat("0").format(db2);
int i3 = Integer.parseInt(str);
System.out.println("double转int的第二种方法:"+i3);
String str2 = new DecimalFormat("0").format(db2);
int i4 = Integer.valueOf(str2).intValue();
System.out.println("double转int的第二种方法:"+i4);
//double转float
/**由于double的精度大于float,因此一般包含小数的数字默认是double类型,double不可以替代float使用,而float可以替代double使用
* 源码中,Float.valueOf()参数是float或者String,故无法转换;
**/
//double转String
//方法一:添加""
str = ""+db;
System.out.println("double转String的第一种方法:"+str);
//方法二:强制转化
String str3 = String.valueOf(db).toString();
System.out.println("double转String的第二种方法:"+str3);
//方法三:当类型是Double对象而非double这种基本类型时还可以直接使用toString()方法
Double db3 = new Double(23.56);
String str4 = db3.toString();
System.out.println("double转String的第三种方法:"+str4);
}
float转所有类型:
//float转所有类型
public static void floatCastAll(int i,double db,float fl,String str){
fl = 2.57f;
//float转int
//方法一:强制转化,易发生精度丢失
i = (int)fl;
System.out.println("float转int的第一种方法:"+i);
//方法二:使用Float类包装,使用intValue()方法
Float fl2 = new Float(3.24);
int i2 = fl2.intValue();
System.out.println("float转int的第二种方法:"+i2);
//float转double
/** float虽然可以转double,但是由于一个是双精度一个是单精度,而且由于这两种类型都是浮点型,计算机是二进制无法准确表示一些十进制数只能近似
* 转化的过程中势必会发生精度丢失,故不推荐使用
**/
db = Double.valueOf(fl).doubleValue();
System.out.println("float转double发生精度丢失:"+db);
//float转String
//方法一:添加""
str = fl+"";
System.out.println("float转String的第一种方法:"+str);
//方法二:强制转化
String str2 = String.valueOf(fl).toString();
System.out.println("float转String的第二种方法:"+str2);
//方法三:如果是Float对象的话,可以直接使用toString方法
String str3 = fl2.toString();
System.out.println("float转String的第三种方法:"+str3);
}
String转所有类型:
//String转所有类型
public static void StringCastAll(int i,double db,float fl,String str){
str = "123";
//String转int
//方法一:使用Integer.parseInt()方法
i = Integer.parseInt(str);
System.out.println("String转int的第一种方法:"+i);
//方法二:使用Integer.valueIf(str).intValue()方法
int i2 = Integer.valueOf(str).intValue();
System.out.println("String转int的第二种方法:"+i2);
//String转double
//方法一:强制转化
db = Double.valueOf(str).doubleValue();
System.out.println("String转double的第一种方法:"+db);
//方法二:使用Double.parseDouble()方法
Double db2 = Double.parseDouble(str);
System.out.println("String转double的第二种方法:"+db2);
//方法三:创建Double对象,该构造函数中参数是String,并返回值的具有相同值的Double对象,当然该str也得是个有效的Double值,否则会报错
Double db3 = new Double(str);
System.out.println("string转double的第三种方法:"+db3);
//String转float
//方法一:强制转换
fl = Float.valueOf(str).floatValue();
System.out.println("String转float的第一种方法:"+fl);
//方法二:使用Float.parseFloat()方法
Float fl2 = Float.parseFloat(str);
System.out.println("String转float的第二种方法:"+fl);
}
补充两种方法之间的区别(以Double.valueOf(str).doubleValue()和Double.parseDouble(str)为例:
/**
* 首先先谈一下Double.valueOf(str)和Double.valueOf(str).doubleValue()的区别
* Double.valueOf(str)是将String类型转为Double类型的对象,假设str = "1.0";等价于Double db = new Double("1.0");
* .doubleValue()就是要求double类型的原始值,等价于double db2 = Double.valueOf("1.0").doubleValue() = 1.0d;
* 再谈Double.valueOf(str)与Double.parseDouble(str)区别
* 查看源码会发现Double.valueOf(str)方法中调用了Double.parseDouble(str)方法,只多了一个将Double对象转为double类型的步骤而已
*/
补充BigDecimal:
/**
* double和float都属于浮点型,计算机是二进制,因此浮点型计算会失去一定的精度(根本原因是因为十进制值通常每一天完全相同的二进制值表示,不够精确只能无限接近。 而对于一些需要特别精确的数值时就不可以出现这种情况比如金融、军事、航天类型的项目,数值必须百分百精确。
* 在商业中使用java.math.BigDecimal来创建BigDecimal对象用于对超过16位有效位的数进行精确运算
* 创建BigDecimal可以使用int、long或者String类型数值作为参数如BigDecimal a = new BigDecimal(12);或者BigDecimal a = new BigDecimal("23");
* 由于double类型的构造方法的结果具有一定的不可预知性即你所谓的0.1其实实际上并非完全等于0.1,而String类型的构造方法的结果是完全可以预知的,所见即所得。因此创建BigDecimal推荐使用String,不推荐使用Double,如果非要传double类型可以先转String在使用。当然BigDecimal转换就很正常的可以转换成多种格式
*/
BigDecimal的使用:
//BigDecimal的使用
public static void bigDecimalUse(){
//错误示例,使用double类型计算出现精度丢失,用该类型存储金额时你就会发现自己莫名其妙的丢钱了。。。。。。
double a = 5.3;
double b = 2.1;
System.out.println("你丢钱了:"+(a-b));
/**
* add(BigDecimal) BigDecimal对象中的值相加,返回该对象
* subtract(BigDecimal) BigDecimal对象中的值相减,返回该对象
* multiply(BigDecimal) BigDecimal对象中的值相乘,返回该对象
* divide(BigDecimal,保留小数点后几位,舍入模式) BigDecimal对象中的值相除,为了防止除不尽报错,需要设定保留小数位和舍入模式
* 这边舍入模式一般使用BigDecimal.ROUND_HALF_UP(四舍五入)和BigDecimal.ROUND_UNNECESSARY(计算精确无需舍入)这两种当然也可以使用这两个对应的数值表示
* setScale(保留小数点后几位,舍入模式) 对BigDecimal进行截取并四舍五入
*/
BigDecimal m = new BigDecimal("127.456");
BigDecimal n = new BigDecimal(48);
BigDecimal k = m.setScale(2,BigDecimal.ROUND_HALF_UP);
System.out.println("m+n="+m.add(n));
System.out.println("m-n+"+m.subtract(n));
System.out.println("m*n="+m.multiply(n));
System.out.println("m/n="+m.divide(n,2,BigDecimal.ROUND_HALF_UP));
System.out.println("m/n="+m.divide(n,2,4));
System.out.println("四舍五入保留两位小数:"+k);
}
BigDecimal转换各种类型:
//BigDecimal转换各种类型
public static void bigDecimalCastAll(int i,double db,float fl,String str){
BigDecimal big = new BigDecimal(24);
//BigDecimal转int
i = big.intValue();
//BigDecimal转double
db = big.doubleValue();
//BigDecimal转float
fl = big.floatValue();
//BigDecimal转String
str = big.toString();
//BigDecimal转long
long lg = big.longValue();
System.out.println("BigDecimal转int:"+i);
System.out.println("BigDecimal转double:"+db);
System.out.println("BigDecimal转float:"+fl);
System.out.println("BigDecimal转String:"+str);
System.out.println("BigDecimal转long:"+lg);
}