[英]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.Integer
或java.lang.Long
或java.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: 另外,如果我理解正确,你知道:
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 现在我们的逻辑很简单:我们将首先检查字符串的长度
If our numbers length < int max length : IT IS INT 如果我们的数字长度<int max length:IT IS INT
If our numbers length == int max length : Check is it INT or LONG 如果我们的数字长度== int最大长度:检查是INT还是LONG
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.