ホームページ  >  記事  >  Java  >  Javaでintをstringに変換する効率とstringをintに変換する効率の違いは何ですか?

Javaでintをstringに変換する効率とstringをintに変換する効率の違いは何ですか?

王林
王林転載
2023-05-12 08:46:16991ブラウズ
    #int から string への変換と string から int への変換の効率の比較

    string から int への変換、2 つの方法

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

    2 番目の方法は、ソース コードを確認して最初の方法を実装することです。

    Javaでintをstringに変換する効率とstringをintに変換する効率の違いは何ですか?

    コメントはおそらくこれを意味します

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

    parseInt() メソッドは valueOf() に実装されています。 2 番目の種類の時間比較は、1 番目の種類よりもはるかに高速です。

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

    int 文字列を変換するには通常 3 つの方法があります

    • 最初の方法:number ""

    • 2 番目の方法: string.valueOf()

    • 3 番目の型: .toString()

    • まずは最初の型について説明します。これは単純で、粗野な。

    • #2 番目のメソッド: 最下層では引き続き .toString() メソッドが使用されます
    • 3 番目のメソッドは 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) - &#39;0&#39;);
            }
            return number;
        }

    上記のコードは、文字列の各文字を走査し、対応する整数に変換し、整数データ数値に 1 つずつ統合します。

    このようなコードを面接官に提出した場合、結果は間違いなく満足のいくものではありません。プログラムの堅牢性を考慮していないためです。カプセル化した関数は 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) - &#39;0&#39;);
            }
            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) == &#39;-&#39;) { // 如果为负数
                negative = true;
                pos++; // 调过第一位符号位
            } else if (str.charAt(0) == &#39;+&#39;) {
                pos++; // 调过第一位符号位
            }
            int number = 0;
            while (pos < str.length()) {
                number *= 10;
                number += (str.charAt(pos) - &#39;0&#39;);
                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) == &#39;-&#39;) { // 如果为负数
                negative = true;
                pos++; // 调过第一位符号位
            } else if (str.charAt(0) == &#39;+&#39;) {
                pos++; // 调过第一位符号位
            }
            int number = 0;
            while (pos < str.length()) {
                if (str.charAt(pos) >= &#39;0&#39; && str.charAt(pos) <= &#39;9&#39;) { // 只有字符在&#39;0&#39;到&#39;9&#39;的范围内,才算正确的字符
                    number *= 10;
                    number += (str.charAt(pos) - &#39;0&#39;);
                    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) == &#39;-&#39;) { // 如果为负数
                negative = true;
                pos++; // 调过第一位符号位
            } else if (str.charAt(0) == &#39;+&#39;) {
                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) >= &#39;0&#39; && str.charAt(pos) <= &#39;9&#39;) { // 只有字符在&#39;0&#39;到&#39;9&#39;的范围内,才算正确的字符
                    if (number > mult) {// 让number和mult比较,如果大于它,则number * 10肯定也就大于最大数
                        throw new NumberFormatException("input string beyond int size");
                    }
                    number *= 10;
                    int digit = str.charAt(pos) - &#39;0&#39;;
                    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; // 如果为负数则返回对应的负数
        }

    上記のコードでは、数値が最大整数を超えるかどうかを判断しますが、まず、数値×10が整数を超える場合は、10倍して最大整数と比較するのではなく、(最大整数/10)の値を比較してみましょう。この範囲を超えるとデータ オーバーフローが発生し、結果の値は 1 つの負の数値になる可能性がありますが、(最大整数/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) == &#39;-&#39;) { // 如果为负数
                negative = true;
                pos++; // 调过第一位符号位
            } else if (str.charAt(0) == &#39;+&#39;) {
                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) >= &#39;0&#39; && str.charAt(pos) <= &#39;9&#39;) { // 只有字符在&#39;0&#39;到&#39;9&#39;的范围内,才算正确的字符
                    if (number < mult) {
                        throw new NumberFormatException("input string beyond int size");
                    }
                    number *= 10;
                    int digit = str.charAt(pos) - &#39;0&#39;;
                    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],最小负数要比最大正数多一位。

    以上がJavaでintをstringに変換する効率とstringをintに変換する効率の違いは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    声明:
    この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。