简体   繁体   English

将字符串表示转换为最小数字对象

[英]Convert String representation to minimal Number Object

Having a String representation of a number(no decimals), what's the best way to convert it to either one of java.lang.Integer or java.lang.Long or java.math.BigInteger ? 有一个数字的字符串表示(没有小数),将它转换为java.lang.Integerjava.lang.Longjava.math.BigInteger之一的最佳方法是什么? The only condition is that the converted type should be of minimal datatype required to hold the number. 唯一的条件是转换后的类型应该是保存数字所需的最小数据类型。

I've this current implementation that works fine, but I would like to know if there's a better code without exception handling. 我这个当前的实现工作正常,但我想知道是否有更好的代码没有异常处理。

package com.stackoverflow.programmer;

import java.math.BigInteger;

public class Test {
    public static void main(String[] args) {

        String number = "-12121111111111111";
        Number numberObject = null;
        try {
            numberObject = Integer.valueOf(number);
        } catch (NumberFormatException nfe) {
            System.out.println("Number will not fit into Integer type. Trying Long...");
            try {
                numberObject = Long.valueOf(number);
            } catch (NumberFormatException nfeb) {
                System.out.println("Number will not fit into Long type. Trying BigInteger...");
                numberObject = new BigInteger(number);
            }
        }
        System.out.println(numberObject.getClass() + " : "
                + numberObject.toString());
    }
}

From what you said, here is what I would have done: 根据你的说法,这就是我要做的:

import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;

public class TestSO09_39463168_StringToMinimalNumber {

    public static void main(String[] args) {
        List<String> strNumbers = Arrays.asList("0", //int
                "123", //int
                "-456", //int
                "2147483700", // Long
                "-2147483700", // Long
                "9223372036854775900", //BigInt
                "-9223372036854775900" //BigInt
                );

        for(String strNumber : strNumbers){
            Number number = stringToMinimalNumber(strNumber);
            System.out.println("The string '"+strNumber+"' is a "+number.getClass());
        }

    }

    public static Number stringToMinimalNumber(String s){
        BigInteger tempNumber = new BigInteger(s);

        if(tempNumber.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0 || tempNumber.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0){
            return tempNumber;
        } else if(tempNumber.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0 || tempNumber.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0){
            return tempNumber.longValue(); //Autobox to Long
        } else {
            return tempNumber.intValue(); //Autobox to Integer
        }

    }

}

You must use a temporary BigInteger, or else you'll end up with lazarov's solution, which is correct, but you can't really do something like that for reason mentionned in the comments. 你必须使用一个临时的BigInteger,否则你最终会得到lazarov的解决方案,这是正确的,但是由于评论中提到的原因你无法真正做到这一点。

Anyway, every BigInteger (the ones that are not returned) will be garbage collected. 无论如何,每个BigInteger(未返回的那些)都将被垃圾收集。 As for autoboxing, I don't think it's that of a bad thing. 至于自动装箱,我认为这不是一件坏事。 You could also make " BigInteger.valueOf(Long.MAX_VALUE)) " as a constant. 你也可以将“ BigInteger.valueOf(Long.MAX_VALUE)) ”作为常量。 Maybe the compiler or the JVM will do this on its own. 也许编译器或JVM会自己做这件事。

I'm not really sure of how efficient it is, and using only BigInteger might be a good idea (as Spotted did), because I serioulsy doubt it would really improve the rest of your code to use the right size, and it might even be error prone if you try to use these Numbers with each other ... But again, it all depend on what you need. 我不太确定它有多高效,只使用BigInteger可能是一个好主意(正如Spotted所做的那样),因为我严重怀疑它会真正改善你的其余代码以使用正确的大小,它甚至可能如果你试图将这些数字相互使用,那就容易出错......但同样,这一切都取决于你需要什么。 (and yes, using Exception as flow control is a really bad idea, but you can add a try catch on the BigInteger tempNumber = new BigInteger(s); to throw your own exception if s is not a number at all) (是的,使用Exception作为流控制是一个非常糟糕的主意,但你可以在BigInteger tempNumber = new BigInteger(s);上添加try catch BigInteger tempNumber = new BigInteger(s);如果s根本不是数字,则抛出你自己的异常)

For recreational purpose, I have made the solution without using a BigInteger, and only with String parsing (this is still not what I recommand to do, but it was fun :) 为了娱乐目的,我已经在没有使用BigInteger的情况下制作了解决方案,并且只使用了String解析(这仍然不是我建议做的,但它很有趣:)

public static final String INT_MAX_VALUE = "2147483647";
public static final String LONG_MAX_VALUE = "9223372036854775807";

public static Number stringToMinimalNumberWithoutBigInteger(String numberStr){
    //Removing the minus sign to test the value
    String s = (numberStr.startsWith("-") ? numberStr.substring(1,numberStr.length()) : numberStr);

    if(compareStringNumber(s, LONG_MAX_VALUE) > 0){
        return new BigInteger(numberStr);
    } else if(compareStringNumber(s, INT_MAX_VALUE) > 0){
        return new Long(numberStr);
    } else {
        return new Integer(numberStr);
    }
}

//return postive if a > b, negative if a < b, 0 if equals;
private static int compareStringNumber(String a, String b){
    if(a.length() != b.length()){
        return a.length() - b.length();
    }
    for(int i = 0; i < a.length(); i++){
        if( a.codePointAt(i) != b.codePointAt(i) ){ //Or charAt()
            return a.codePointAt(i) - b.codePointAt(i);
        }
    }
    return 0;
}

Please don't use exceptions for handling flow control, this is a serious anti-pattern (also here ). 请不要使用异常来处理流量控制,这是一个严重的反模式 (也在这里 )。

As you mentionned in the comments, the real thing you've been asked is to convert a List<String> into a List<Number> . 正如您在评论中提到的那样,您被问到的真实事实是将List<String>转换为List<Number> Also, if I understand correctly, you know that: 另外,如果我理解正确,你知道:

  • You should encounter only numbers without decimals 您应该只遇到没有小数的数字
  • The biggest value you can encounter is possibly unbound 您可能遇到的最大价值可能是未绑定的

Based on that, the following method will do the job in a more clever way: 基于此,以下方法将以更聪明的方式完成工作:

private static List<Number> toNumbers(List<String> strings) {
    return strings.stream()
                  .map(BigInteger::new)
                  .collect(Collectors.toList());
}

Eidt: if you're not very familiar with the stream concept, here's the equivalent code without streams: Eidt:如果您对流概念不是很熟悉,这里是没有流的等效代码:

private static List<Number> toNumbers(List<String> strings) {
    List<Number> numbers = new ArrayList<>();
    for (String s : strings) {
        numbers.add(new BigInteger(s));
    }
    return numbers;
}

Well if you want to do it "by hand" try something like this: 好吧,如果你想“手动”做这样的事情:

We define the max values as strings : 我们将最大值定义为字符串:

String intMax = "2147483647";
String longMax = "9223372036854775807";

and our number: 和我们的号码:

String ourNumber = "1234567890"

Now our logic will be simple : We will check lenghts of strings firstly 现在我们的逻辑很简单:我们将首先检查字符串的长度

  1. If our numbers length < int max length : IT IS INT 如果我们的数字长度<int max length:IT IS INT

  2. If our numbers length == int max length : Check is it INT or LONG 如果我们的数字长度== int最大长度:检查是INT还是LONG

  3. If our numbers length > int max length : 如果我们的数字长度> int最大长度:

    3.1 If our numbers length < long max length : IT IS LONG 3.1如果我们的数字长度<长最大长度:它是长的

    3.2 If our numbers length == long max length : Check is it LONG or BIG INTEGER 3.2如果我们的数字长度==长最大长度:检查是LONG还是BIG INTEGER

    3.3 If our numbers length > long max length : IT IS BIG INTEGER 3.3如果我们的数字长度>长最大长度:它是大整数

The code should look something like this (I have not tried to compile it may have syntax or other errors) : 代码应该看起来像这样(我没有尝试编译它可能有语法或其他错误):

if(ourNumber.lenght() < intMax.length ){
    System.out.println("It is an Integer");
} else if(ourNumber.lenght() == intMax.length){
    // it can be int if the number is between 2000000000 and 2147483647
            char[] ourNumberToCharArray = ourNumber.toCharArray();
            char[] intMaxToCharArray = intMax.toCharArray();
            int diff = 0;
            for(int i = 0; i < ourNumberToCharArray.length; i++) {  
                diff  = Character.getNumericValue(intMaxToCharArray[i]) - Character.getNumericValue(ourNumberToCharArray[i]);
                if(diff > 0) { 
                    System.out.println("It is a Long");
                    break;                  
                } else if(diff < 0) {
                    System.out.println("It is an Integer");
                        break;
                }
            }
            if(diff == 0){
              System.out.println("It is an Integer");  
            }   
} else { 
    if(ourNumber.lenght() < longMax.length()) {
        System.out.println("It is a Long");
    } else if(ourNumber.lenght() == longMax.length()){
            char[] ourNumberToCharArray = ourNumber.toCharArray();
            char[] longMaxToCharArray = longMax.toCharArray();
            int diff = 0;
            for(int i = 0; i < ourNumberToCharArray.length; i++) {  
                diff  = Character.getNumericValue(longMaxToCharArray[i]) - Character.getNumericValue(ourNumberToCharArray[i]);
                if(diff > 0) { 
                    System.out.println("It is a BigInteger");
                    break;                  
                } else if(diff < 0) {
                    System.out.println("It is a Long");
                        break;
                }
            }   
            if(diff == 0){
              System.out.println("It is a Long");  
            }   
    } else { 
        System.out.println("It is a BigInteger");
    }
}

Then logic that checks if the numbers match or not is the same in both cases you can but it in a function for example. 然后检查数字是否匹配的逻辑在两种情况下都是相同的,但是它可以在一个函数中,例如。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何将数字的二进制表示形式的Java链接列表转换为数字的十进制表示形式的字符串? - How to convert a java linked list of a binary representation of a number to a String of the decimal representation of a number? 在Java中将Object的String表示形式转换回原始类型的Object - Convert a String representation of Object back to an Object of original type in java Android(Java)将hh:mm:ss时间字符串转换为数字表示形式 - Android (Java) convert a hh:mm:ss time String into a number representation 数字的字符串表示形式 - String representation of a number Java:如何将任何Object转换为数据的String表示形式 - Java: How to convert any Object to a String representation of the data Java中对象的自定义字符串表示形式 - Custom String representation of an Object in Java JSON 表示 Map<string, object></string,> - JSON representation of Map<String, Object> 如何将字符串的二进制表示形式转换回字符串? - How to convert a binary representation of a string back into a string? 无法将[text / plain,UTF-8]表示转换为类java.lang.String的对象 - Unable to convert a [text/plain,UTF-8] representation into an object of class java.lang.String 将byte []的字符串表示形式转换回byte [] - Convert a String representation of byte[] back to an byte[]
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM