java中int转string与string转int的效率对比

目录
  • int转string与string转int的效率对比
    • string转int,两种方法
    • int转string一般用三种方法
  • string转int问题分析
    • 分析一波
      • 1、针对传入的字符串为空对象或者字符串为空的字符串
      • 2、针对符号位的处理
      • 3、针对错误字符的处理
      • 4、针对整形数据超出范围的处理
      • 5、int数据范围的讨论
      • 原码、反码、补码
    • 小结一下

int转string与string转int的效率对比

string转int,两种方法

Interger.parseInt(String)
Interger.valueOf(String).intValue()

第二种方法可以去看源码,实现了第一种方法。

注释大概就是这样的意思

/**
      *返回一个包含整数的对象
      *指定的{@ String String}的值。 这个说法是
      *被解释为表示一个有符号的十进制整数
      *就好像这个论据是给予{@link的
      * #parseInt(java.lang.String)}方法。 结果是一个
      表示整数值的整数对象
      *由字符串指定。
     *
      换句话说,这个方法返回一个{@code Integer}
      *对象等于以下值:
     *
      * <blockquote>
      * {@code new Integer(Integer.parseInt(s))}
      * </ blockquote>
     *
      * @param是要解析的字符串。
      * @返回一个保存值的{整数}对象
      *由字符串参数表示。
      * @exception NumberFormatException如果字符串不能被解析
      *作为一个整数。
     */

在valueOf()里面实现了parseInt()方法。时间对比第二种比第一种要快了很多。

 Integer.parseInt(str) : 21
 Integer.valueOf(str).intValue() : 14

int 转string一般用三种方法

  • 第一种:number + ""
  • 第二种:string.valueOf()
  • 第三种:.toString()
  • 先说第一种,简单粗暴。
  • 第二种方法:底层使用的依旧是.toString()方法
  • 第三种就是toString()

上代码。

int num = 888888;

        //(1)num + ""
        long start = System.currentTimeMillis();//得到开始运行时系统时间
        for(int i=0; i<100000; i++){
            String str = num + "";
        }
        long end = System.currentTimeMillis();//得到结束运行时系统时间
        System.out.println("num + \"\" : " + (end - start));

        //(2)String.valueOf(num)
        start = System.currentTimeMillis();
        for(int i=0; i<100000; i++){
            String str = String.valueOf(num);
        }
        end = System.currentTimeMillis();
        System.out.println("String.valueOf(num) : " + (end - start));

        //(3)Integer.toString(num)
        start = System.currentTimeMillis();
        for(int i=0; i<100000; i++){
            String str = Integer.toString(num);
        }
        end = System.currentTimeMillis();
        System.out.println("Integer.toString(num) : " + (end - start));

结果就是

num + "" : 82
String.valueOf(num) : 32
Integer.toString(num) : 9

经过多次的反复测试,toString()是最快的,num+""是最慢的,在使用String.valueOf()中源码是这样的。

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

也就是说在使用的时候,不用去判断所传的对象是否为null,但是尤其注意,如果传的为空,返回来的是一个为null的字符串而不是null值,这个地方需要谨记。

string转int问题分析

相信很多同学在面试时都遇到过这样一个问题,要求封装一个函数,将String类型转换为int类型。这个看似简单的问题其实隐藏着很多细节,要想真正封装好这个函数并不容易。面试官要考察的其实并不是算法本身的难度,这个问题的算法其实没有什么难度可言,主要要考察的是程序员写代码的仔细程度,考虑问题是否全面,也就是说,我们要尽可能的让代码具有鲁棒性。下面我们一步步的分析这个问题中隐藏的细节。

分析一波

首先我们不考虑任何的异常处理,假设函数的调用者传入的数据都是正确的,很容易就可以写出下面的代码:

    public int strToInt(String str) {
        int number = 0;
        for (int i=0; i<str.length(); i++) {
            number *= 10;
            number += (str.charAt(i) - '0');
        }
        return number;
    }

上面的代码将遍历字符串的每一位字符,并将其转换为对应的整数,然后将其一一融入到整形数据number中。

如果你给面试官提交的是这样一份代码,结果肯定不会满意。因为你没有考虑到程序的鲁棒性,我们封装的函数相当于API接口,是提供给所有开发者调用的,难免其他开发者不会传入一些奇怪的参数,而这段代码对异常参数没有做任何处理,一旦传入异常参数,程序将直接崩溃。下面我们一步步来完善这个函数,提高其鲁棒性。

1、针对传入的字符串为空对象或者字符串为空的字符串

    public int strToInt(String str) throws NumberFormatException{
        if (str == null || str.contentEquals("")) { // 如果传入的字符串为空对象或者传入的字符串为空字符串,则抛出异常
            throw new NumberFormatException("null or empty string"); // 这里直接利用java封装好的异常类,当然我们也可以自己封装异常类,面试官要考察的不是对异常类的封装,而是你要知道要处理异常情况
        }
        int number = 0;
        for (int i=0; i<str.length(); i++) {
            number *= 10;
            number += (str.charAt(i) - '0');
        }
        return number;
    }

首先我们字符串是否为空或者是否为空的字符串,如果是,则直接抛出异常,这里我们使用的是Java封装好的异常类NumberFormatException,当然我们也可以自己封装异常类,面试官要考察的不是对异常类的封装,而是你要知道要处理异常情况。

2、针对符号位的处理

这个我们最好提前问一下面试官,有没有可能传入的是负数,当为正数时,是否允许带符号位,如果是的话,我们就要针对符号位进行处理,负数的第一个字符是“-”,我们只要判断第一个字符是否为“-”就可以知道传入的是否为负数了,如果正数允许带符号位,那边第一个字符有可能是“+”,我们也要做对应的处理:

    public int strToInt(String str) throws NumberFormatException{
        if (str == null || str.contentEquals("")) { // 如果传入的字符串为空对象或者传入的字符串为空字符串,则抛出异常
            throw new NumberFormatException("null or empty string"); // 这里直接利用java封装好的异常类,当然我们也可以自己封装异常类,面试官要考察的不是对异常类的封装,而是你要知道要处理异常情况
        }
        boolean negative = false; // negative为true表示是负数,反之为正数
        int pos = 0;
        if (str.charAt(0) == '-') { // 如果为负数
            negative = true;
            pos++; // 调过第一位符号位
        } else if (str.charAt(0) == '+') {
            pos++; // 调过第一位符号位
        }
        int number = 0;
        while (pos < str.length()) {
            number *= 10;
            number += (str.charAt(pos) - '0');
            pos++;
        } 
        return negative ? -number : number; // 如果为负数则返回对应的负数
    }

3、针对错误字符的处理

函数的调用者可能会传入一下乱七八糟的字符串,比如“abc23123”,针对这种情况我们也要做对应的处理,应该给调用者抛出一个异常,告知其传入的字符串是非法字符串:

    public int strToInt(String str) throws NumberFormatException{
        if (str == null || str.contentEquals("")) { // 如果传入的字符串为空对象或者传入的字符串为空字符串,则抛出异常
            throw new NumberFormatException("null or empty string"); // 这里直接利用java封装好的异常类,当然我们也可以自己封装异常类,面试官要考察的不是对异常类的封装,而是你要知道要处理异常情况
        }
        boolean negative = false; // negative为true表示是负数,反之为正数
        int pos = 0;
        if (str.charAt(0) == '-') { // 如果为负数
            negative = true;
            pos++; // 调过第一位符号位
        } else if (str.charAt(0) == '+') {
            pos++; // 调过第一位符号位
        }
        int number = 0;
        while (pos < str.length()) {
            if (str.charAt(pos) >= '0' && str.charAt(pos) <= '9') { // 只有字符在'0'到'9'的范围内,才算正确的字符
                number *= 10;
                number += (str.charAt(pos) - '0');
                pos++; 
            } else {
                throw new NumberFormatException("invalid string"); // 当字符是其他字符时,抛出异常告知调用者传入的字符串错误
            }
        } 
        return negative ? -number : number; // 如果为负数则返回对应的负数
    }

4、针对整形数据超出范围的处理

调用者传入的字符串可能是一个很长的字符串,转换为整数可能超出了整数的存储范围,比如“12345678674324334”,在这种情况下,我们要抛出一个异常告知调用者传入的字符串超出了整形的范围:

    public int strToInt(String str) throws NumberFormatException{
        if (str == null || str.contentEquals("")) { // 如果传入的字符串为空对象或者传入的字符串为空字符串,则抛出异常
            throw new NumberFormatException("null or empty string"); // 这里直接利用java封装好的异常类,当然我们也可以自己封装异常类,面试官要考察的不是对异常类的封装,而是你要知道要处理异常情况
        }
        boolean negative = false; // negative为true表示是负数,反之为正数
        int pos = 0;
        if (str.charAt(0) == '-') { // 如果为负数
            negative = true;
            pos++; // 调过第一位符号位
        } else if (str.charAt(0) == '+') {
            pos++; // 调过第一位符号位
        }
        int limit = negative ? (-Integer.MIN_VALUE) : Integer.MAX_VALUE;
        int mult = limit / 10; // 记录最大数/10,让number和这个数比较,如果大于它,则number * 10肯定也就大于最大数
        int number = 0;
        while (pos < str.length()) {
            if (str.charAt(pos) >= '0' && str.charAt(pos) <= '9') { // 只有字符在'0'到'9'的范围内,才算正确的字符
                if (number > mult) {// 让number和mult比较,如果大于它,则number * 10肯定也就大于最大数
                    throw new NumberFormatException("input string beyond int size");
                }
                number *= 10;
                int digit = str.charAt(pos) - '0';
                if (number > limit - digit) { // 这里不能用number + digit > limit来判断,因为number + digit可能超出整数的存储范围,相加后的数可能是一个负数,但是limit - digit肯定不会超出
                    throw new NumberFormatException("input string beyond int size");
                } else {
                    number += digit;
                }
                pos++;
            } else {
                throw new NumberFormatException("invalid string"); // 当字符是其他字符时,抛出异常告知调用者传入的字符串错误
            }
        } 
        return negative ? -number : number; // 如果为负数则返回对应的负数
    }

上面的代码中,我们判断number是否会超出最大整数时首先是先让其(最大整数/10)的值比较,而不是让其乘以10与最大整数比较,这是因为number * 10如果超出了整数范围,则会造成数据溢出,其得到的值可能是一个负数,而(最大整数/10)的值是不会数据溢出的,这也是一个小细节。可能你以为这样这个函数就完美了,但是现在我要告诉你,上面的写法是错误的。

为什么呢?这要从整数的范围说起,整数的取值范围是(-2^31)至(2^31 - 1),从绝对值的角度看,最小负数相比于最大正数大1。所以上面代码中(-Integer.MIN_VALUE)会超出整形的范围,造成数据溢出,也就是说上面的代码对负数最小范围的限制的处理是错误的。那么怎么解决这个问题呢?

我们换个角度思考,最小负数的绝对值比最大正数的绝对值大1,那(-Integer.MAX_VALUE)的值肯定不会超出整数的范围,我们现在的程序是以正数的方式处理,如果反过来已负数的方式处理,问题不就解决了吗?修改代码如下:

    public int strToInt(String str) throws NumberFormatException{
        if (str == null || str.contentEquals("")) { // 如果传入的字符串为空对象或者传入的字符串为空字符串,则抛出异常
            throw new NumberFormatException("null or empty string"); // 这里直接利用java封装好的异常类,当然我们也可以自己封装异常类,面试官要考察的不是对异常类的封装,而是你要知道要处理异常情况
        }
        boolean negative = false; // negative为true表示是负数,反之为正数
        int pos = 0;
        if (str.charAt(0) == '-') { // 如果为负数
            negative = true;
            pos++; // 调过第一位符号位
        } else if (str.charAt(0) == '+') {
            pos++; // 调过第一位符号位
        }
        int limit = negative ? Integer.MIN_VALUE : (-Integer.MAX_VALUE);
        int mult = limit / 10;
        int number = 0;
        while (pos < str.length()) {
            if (str.charAt(pos) >= '0' && str.charAt(pos) <= '9') { // 只有字符在'0'到'9'的范围内,才算正确的字符
                if (number < mult) {
                    throw new NumberFormatException("input string beyond int size");
                }
                number *= 10;
                int digit = str.charAt(pos) - '0';
                if (number < limit + digit) {
                    throw new NumberFormatException("input string beyond int size");
                } else {
                    number -= digit;
                }
                pos++;
            } else {
                throw new NumberFormatException("invalid string"); // 当字符是其他字符时,抛出异常告知调用者传入的字符串错误
            }
        } 
        return negative ? number : -number;
    }

OK,现在我们把能够想到的异常情况处理了。再来考虑一个问题,为什么整形数据的范围是(-2^31)至(2^31 - 1),最小负数的绝对值比最大正数的绝对值要大1呢?

5、int数据范围的讨论

我们知道,一个int类型占四个字节,也就是32位,其中第一位是符号位,符号位为0表示正数,为1表示负数,其余31位表示数值。正常来说int类型的数据范围应该是(-2^31-1)到(2^31-1),为什么负数会多一位呢?

我们首先看一下Java代码中对Integer.MAX_VALUE和Integer.MIN_VALUE的定义:

    /**
     * A constant holding the minimum value an {@code int} can
     * have, -2<sup>31</sup>.
     */
    public static final int   MIN_VALUE = 0x80000000;
 
    /**
     * A constant holding the maximum value an {@code int} can
     * have, 2<sup>31</sup>-1.
     */
    public static final int   MAX_VALUE = 0x7fffffff;

原码、反码、补码

我们知道,在计算机中,数据都是以二进制的形式存储的,比如,数字10,其二进制形式就是1010。

一个字节有8位,每位可以存储一个01字符,byte类型占1个字节,也就是8位,其中,最高位是符号位,用来表示数值是正数还是负数,符号位为0表示正数,符号位为1表示负数。我们先来看一下原码、反码、补码的定义:

  • 原码:符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值。
  • 反码:正数的反码是其本身;负数的反码是在其原码的基础上, 符号位不变,其余各个位取反。
  • 补码:补码的表示方法是:正数的补码就是其本身;负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1。 (即在反码的基础上+1)

正数的原码、反码、补码都是其本身;负数的反码是在其原码的基础上,符号位不变,其余个位取反,负数的补码是其反码的基础上+1。

举例说明(下面都以byte类型进行举例):

数据 原码 反码 补码
10 00001010 00001010 00001010
-10 10001010 11110101 11110110

计算机中,数据都是以补码的形式存储的。为什么要以补码的形式存储呢?有两个原因:

1、如果数值以补码的形式保存,对一个数进行求补运算,可以得到其相反值

求补运算:将一个数(包括正数和负数)所有二进制位(包括符号位和数值位)取反,然后在最低位加上1。

为什么对一个数进行求补运算,可以得到其相反值呢?我们先来分析一下求补运算的定义,现将所有的二进制取反,然后+1,首先一个数和它所有位取反得到的数相加,其结果肯定是11111111,这是因为它们每一位都不一样,然后将结果+1,即11111111 + 1,结果是1 00000000,最高位的1已经溢出,换种方式说,如果以f(n)表示对n进行求补运算,那么对于任意的范围内的数,可以得到:

n + f(n) = 1 00000000

f(n) = 1 00000000 - n

而对于一个正数来说,对其进行求补运算其实得到的就是它的相反数的补码(负数的补码符号位保持不变,其他为全部取反再+1,因为正数和负数的符号位本来就不一样,所以对一个正数进行求补其实得到的就是它的相反数的补码)。

那么对于一个负数来说呢?对其进行求补运算是否能够得到其对应的正数的补码呢?

假设n>0,根据上面可知:

f(n) = 1 00000000 - n

对f(n)进行求补运算,有:

f(f(n)) = f(1 00000000 - n) = 1 00000000 - (1 00000000 - n) = n

其中,1 00000000 - n表示n对应负数的补码,对其进行求补运算得到的就是n,正数的补码就是其原码。

由上可知:如果数值以补码的形式保存,对一个数进行求补运算,可以得到其相反值,即:f(n) = -n

2、方便减法运算

如果数值以补码的方式存储,可以将减法变为加法,省去了减法器,通过上面的推导,如果数据以补码的方式存储,以f(n)表示对n进行求补运算,可以得到:

f(n) = -n

那么现在我们需要计算m - n,应该要怎么计算呢?如果以补码的方式存储,那么就有:

m - n = m + (-n) = m + f(n)

也就是说,减去一个数只需要加上对其进行求补运算后得到的值即可。

3、使用补码存储数据,可以对任意的两个数直接进行相加运算,不用考虑符号位

4、通过补码形式存储,规定10000000对应的负数的最小值,也就是-128。

由上面可知,如果是byte类型,数据范围应该为[-128,127],最小负数要比最大正数多一位。

小结一下

我们在写代码时,不能仅仅注意代码的功能,还要考虑到代码的鲁棒性,比如参数的正确性、参数的范围以及异常情况的处理等等。只有这样,我们写出的程序才能更加健壮,这也是一个优秀开发者的基本素质。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Java中Integer两种转int方法比较

    方法一: Integer.parseInt(); 返回的是一个 int 的值. 方法二: new Integer.valueof(); 返回的是 Integer 的对象. new Integer.valueof().intValue(); 返回的也是一个 int 的值. 笔试应用例题: 设有下面两个赋值语句: a = Integer.parseInt("123"); b = Integer.valueOf("123").intValue(); 下述说法正确的是( 

  • Java Enum和String及int的相互转化示例

    一.定义性别枚举 枚举(enum),是指一个经过排序的.被打包成一个单一实体的项列表.使用枚举增加程序可读性.降低耦合性. /** * 性别枚举 */ public enum Gender { male("男"),female("女"); private String name; private Gender(String name) { this.name = name; } public String getName() { return name; } } 二

  • Java之int和string类型转换详解

    int.String的类型转换 int -> String int i=12345; String s=""; 第一种方法:s=i+""; 第二种方法:s=String.valueOf(i); 这两种方法有什么区别呢?作用是不是一样的呢?是不是在任何下都能互换呢? String -> int s="12345"; int i; 第一种方法:i=Integer.parseInt(s); 第二种方法:i=Integer.valueOf(s

  • Java中string和int的互相转换问题

    int -> String int i=12345; String s=""; 核心:s=i+""; String -> int s="12345"; int i; 核心:i=Integer.parseInt(s); package com.fry.util; public class Transfer { public void stringToInt(){ String id="20171091"; int n

  • 实例分析Java中public static void main(String args[])是什么意思

    本文实例讲述了Java中public static void main(String args[])的来龙去脉.分享给大家供大家参考,具体如下: public static void main(String[] args) 这绝对不是凭空想出来的,也不是没有道理的死规定,而是java程序执行的需要. jvm在试图运行一个类之前,先检查该类是否包含一个特殊方法.这个方法必须是公有的,以便在任何位置都能访问得到.这个方法必须是static的,因为这个方法不能依赖任何该类的实例即可运行,而非stati

  • Java中5种方式实现String反转

    这里介绍Java中5中实现String反转的方式. 一.数组实现String反转 //数组实现String反转 public String reverseByArray(){ if(str == null || str.length() == 1){ return null; } char[] ch = str.toCharArray();//字符串转换成字符数组 for(int i = 0 ; i < ch.length/2 ; i++){ char temp = ch[i]; ch[i] =

  • Java中StringUtils工具类进行String为空的判断解析

    判断某字符串是否为空,为空的标准是str==null或str.length()==0 1.下面是StringUtils判断是否为空的示例: StringUtils.isEmpty(null) = true StringUtils.isEmpty("") = true StringUtils.isEmpty(" ") = false //注意在 StringUtils 中空格作非空处理 StringUtils.isEmpty(" ") = fals

  • 全面解释java中StringBuilder、StringBuffer、String类之间的关系

    1. String 类 String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且大量浪费有限的内存空间. String a = "a"; //假设a指向地址0x0001 a = "b";//重新赋值后a指向地址0x0002,但0x0001地址中保存的"a"依旧存在,但已经不再是a所指向的,a 已经指向了其它地址. 因此String的操作都是改变赋值地址而不是改变值操作. 2. StringBuf

  • Java中字符串常见题之String相关讲解

    今天给大家带来的是在面试中经常被问到的一道题: 无论在Java还是Android中,String是一个很常见的类,但是大家真的很了解吗,我这里有几个题: 1. String str1 = "abc"; String str2 = new String("abc"); 这两种创建String对象的方法有什么不同? 2. String s = "a" + "b" + "c" + "d"; 这

  • 如何解决java中遇到的for input string: "" 报错问题

    做Java开发的人,一生至少该有一次或多次遇到[For input String: ""]这样的报错问题,原因通常都是出现在字符串强制转换成数值类型的时候报的错. 比如: String yanggb = ""; int num = Integer.parseInt(yanggb); 这段代码就会报出[For input String: ""]的错误信息. 这个时候的解决办法也很简单,只需要在类型转换的时候做一下空值处理就行了. String ya

  • Java中break、continue、return语句的使用区别对比

    break.continue.return之间的区别与联系 在软件开发过程中,逻辑清晰是非常之重要的. 代码的规范也是非常重要的.往往细节决定成败.在编写代码的时候,一定要理解语言的作用以及使用的方法和场景.下面来介绍一下break.continue.return三者的区别和联系. 1. break : (1).结束当前整个循环,执行当前循环下边的语句.忽略循环体中任何其它语句和循环条件测试. (2).只能跳出一层循环,如果你的循环是嵌套循环,那么你需要按照你嵌套的层次,逐步使用break来跳出

  • Java中关于String的全面解析

    前言 基于字符串String在java中的地位,关于String的常识性知识就不多做介绍了,我们先来看一段代码 public class Test { public static void main(String[] args) { String a = "abc"; String b = "abc"; String c = new String("abc"); System.out.println(a==b); System.out.print

  • 关于Java中byte[] 和 String互相转换问题

    通过用例学习Java中的byte数组和String互相转换,这种转换可能在很多情况需要,比如IO操作,生成加密hash码等等. 除非觉得必要,否则不要将它们互相转换,他们分别代表了不同的数据,专门服务于不同的目的,通常String代表文本字符串,byte数组针对二进制数据 通过String类将String转换成byte[]或者byte[]转换成String 用String.getBytes()方法将字符串转换为byte数组,通过String构造函数将byte数组转换成String 注意:这种方式

  • 浅析Java中对象的创建与对象的数据类型转换

    Java:对象创建和初始化过程 1.Java中的数据类型     Java中有3个数据类型:基本数据类型(在Java中,boolean.byte.short.int.long.char.float.double这八种是基本数据类型).引用类型和null类型.其中,引用类型包括类类型(含数组).接口类型.     下列语句声明了一些变量: int k ; A a; //a是A数据类型的对象变量名. B b1,b2,-,b10000;// 假定B是抽象类或接口. String s; 注意:从数据类型

随机推荐