What's the right way to represent phone numbers? - java

I'm having trouble representing a mobile number in one of my applications.
I was wondering if there is an Integer class that will allow you to store such a number starting with 0417254482. Perhaps using a string be a more appropriate?
At present when I'm trying to use represent a phone number with ints, doubles longs I seem to store random numbers and not the numbers I meant to store.

Use String. Aside from anything else, you won't be able to store leading zeroes if you use integers. You definitely shouldn't use int (too small) float or double (too much risk of data loss - see below); long or BigInteger could be appropriate (aside from the leading zeroes problem), but frankly I'd go with String. That way you can also store whatever dashes or spaces the user has entered to make it easier to remember the number, if you want to.
In terms of the "data loss" mentioned above for float and double - float definitely doesn't have enough precision; double could work if you're happy that you'll never need more than 16 digits (a couple fewer than you get with long) but you would need to be very, very careful that anywhere you convert the value back from double to string, you got the exact value. Many formatting conversions will give you an approximation which may be accurate to, say, 10 significant digits - but you'd want an exact integer. Basically, using floating point for phone numbers is a fundamentally bad idea. If you have to use a fixed-width numeric type, use a long, but ideally, avoid it entirely.

Think about this: Is a phone number really a number? Does it make sense adding (or make another arithmetic operation) with phone numbers? Phone numbers are codes, they're usually represented with numbers, but that's just a convention and, maybe, in another country the use letters too (I've just realized, what about international phone numbers? they have a + at the beginning.
You have to think about the nature of the things you want to represent, and then, find the most suitable representation.

If you want to do validation and normalization you probably want to rely on a library that does it properly for you. https://github.com/googlei18n/libphonenumber is one of the most common options.

Although phone numbers are named numbers, they are normally not numbers (e.g. leading zeros, country prefix +XX, ...).
So there are two possibilities to represent a phone number correctly inside a program:
Using String to keep the whole number like entered.
Using a custom data type that offers additional support for phone number features
public class PhoneNumber implements Comparable<PhoneNumber>{
private String countryCode;
private String areaCode;
private String subscriberNumber;
// Constructor(s)
// Getter
// HashCode + Equals
// compareTo
#Override
public String toString(){
return countrycode + " " + areaCode + " " + subscriberNumber;
}
}
It's really interesting to look at all the different conventions that are used internationally

Create your own PhoneNumber class with a private field of type String to represent it.
public class PhoneNumber {
private String number;
public PhoneNumber(String number) {
//check validity of number
this.number = number;
}
//getter, comparator, etc...
}
You could also represnt the number with long or BigInteger if all phone numbers have the same length, but be careful with leading zeros.
A phone number is not really an integer (or a string). It is something else which shuld have a class of its own.
EDIT:
one more thing: I wouldn't implement a setter for this class because a phone number object would better be immutable

You should use a string or a more specialized data structure.
The main reason is that the operations that you can do on phone numbers are lexicographic, and not arithmetic.
e.g. You can say that phone numbers for France start with +33, but you cannot assume they are in a numerical range.
These other arguments are not valid in my opinion
a phone number can include * or #. This symbols can be transported on phone lines, but they are not part of the phone number itself, and I consider it's out of scope.
a phone number can start with leading zeros. Local phone numbers can, but they are a limited representation in the first place. International phone numbers start with a country code, and none of them has a leading zero. Hence no international phone number has leading zeros.
a phone number starts with +. A number can perfectly represent this, by simply being positive. Also starting with + is just a representation of E164 numbers, so that they can be distinguished from local numbers. They really don't have to, if you only manipulate E164 numbers.
a phone number can contain spaces or parentheses. This is absurd, because it's just textual representation of the number. You shouldn't store this as people can have different personal preferences to separate groups of digits (., -, , etc.).

You should use string to support numbers with leading zeros. The code you provided was:
Order order1 = new PickUpOrder(orderTime, 0473519954);
//The pickup order requires an orderTime (String) and a contact number(Int). Heres
//the constructor for PickUpOrder.
public PickUpOrder(Date orderTime, String number)
{
discount = .2;
phoneNumber = number;
super.setOrderTime(orderTime);
//Test print
System.out.println(phoneNumber)
//reads int as 74049273 instead of 0473519954
}
In the constructor, the number is string but when you call the constructor you used an int for phone number. There must have been a compile error here in java I think. Is this the same code you compiled?

Every number have infinity amount of zeros on the left and right side,
To represent it you should use a string formating
class PhoneNumber implements Comparable<PhoneNumber> {
private Long number;
public PhoneNumber(Long number) {
this.number = number;
}
public Long getNumber() {
return this.number;
}
public boolean equals(Object object) {
if (getNumber() == null && object == null) {
return true; //or false its depend
}
return getNumber().equals(object);
}
public int compareTo(PhoneNumber that) {
if(that == null) {
return -1;
}
Long thisNumber = getNumber();
Long thatNumber = that.getNumber();
if (thisNumber == null && thatNumber == null) {
return 0; //or -1
}
if (thisNumber == null && thatNumber != null) {
return -1;
}
return thisNumber.compareTo(thatNumber);
}
#Override
public String toString() {
return String.format("%010d", getNumber());
}
}
Used %010d mean
%[argument_index$][flags][width][.precision]conversion
flag 0 - padding zeros
10 - amount of padding zeros
d - decimal integer
The implementation of interface Comparable give you the posibility to sort List.
List<PhoneNumber> phoneNumbers = new ArrayList();
phoneNumbers.add(new PhoneNumber (123L);
phoneNumbers.add(new PhoneNumber (123777L);
phoneNumbers.add(new PhoneNumber (125L);
phoneNumbers.add(new PhoneNumber (124L);
phoneNumbers.add(new PhoneNumber (126L);
Collections.sort(phoneNumbers);
for(PhoneNumber phoneNumber : phoneNumbers) {
System.Console.Out.WriteLine(phoneNumber);
}
The output is
0000000000
0000000123
0000000124
0000000125
0000000126
0000123777
Comparable
String Formatter

I would suggest not use primitive data type.
Reason: Primitives cannot accept special characters such as +,-,(, and, ). If you accept phone numbers in this format +1(xxx)-xxx-xxxx.

Related

How to always keep 2 decimal places in Java

I want to round off any double to a String with 2 decimal places in Java.
I have tried using DecimalFormat but it doesn't give the expected results.
Any help would be appreciated.
Ex: I/P: 3402100.5323
I want to convert this to:
O/P: 34.02
I've tried using DecimalFormat("##,##,##0.00", new DecimalFormatSymbols(Locale.US))
but this results in 34,02,100.53 whereas I want it to output 34.02
PS: If the I/P is 34.02 I would expect it to remain same even after applying the formatting
In my opinion, this can be achieved in 2 steps:
Transform the number into your customised
round-off. (3402100.5323 to 34.021005323). Divide the input with power of 10 to make it round to 2 digits.
Then transformed number can be pretty-printed to truncate value after 2 decimals (34.021005323 to 34.02)
public static void main(String[] args) {
double input = 3402100.5323;
double output = input / getDivisor(input);
System.out.printf("%.2f%n", output);
}
private static double getDivisor(double input) {
int length = String.valueOf((long) input).length();
return Math.pow(10, length - 2) ;
}
Output: 34.02
String.format("%0.2f", 34.021005323)
See
https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#format(java.lang.String,%20java.lang.Object...) and
https://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html#syntax
Turning one number into something completely different is, naturally, not the job of decimalformat.
To get from a number representing 3402100.5323 to the string "34.02", first you'd have to get a number that is closer to "34.02". In other words, divide by 10000.0 first.
From there, String.format("%.2f") seems like an easy path: That renders any double to a string, but never using more than 2 digits after the decimal separator. If you want 3400000.123 to turn into "34.00" and not "34", you can make that String.format("%.02f") to force the zeroes.
public String renderWhateverThatIs(double in) {
return String.format("%.02f", in / 100000.0);
}
renderWhateverThatIs(3402100.5323);
> 34,02
Note that the machine locale will dictate if you see a dot or a comma as separator. You can force the issue by explicitly passing a locale to format.
I think what you're looking for is the java.math.BigDecimal class (https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html).
In your case, it would look like this:
BigDecimal rounded = BigDecimal.valueOf(yourDoubleValueHere).setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println(rounded); // 34.02
It can replace doubles (with more complex syntax though) by basically storing numbers in their decimal form, which means you could make operations on it and keep having two decimal places and avoid rounding issues.
EDIT: after thinking about it, it's probably overkill since you only want to get a String with the rounded value, but I'll leave it there just in case.
I don’t believe you can achieve what you want (First 4 digits converted into a 2 digit double with 2 decimal places) in a single step. I’ll break down the steps for an approach that I would try:
Convert the input double to a string
double d = 3402100.5323;
String dStr1 = String.valueOf(d); // dStr1 will be “3402100.5323”
Next, remove the decimal from the string
String dStr2 = dStr1.replace(‘.’,’’); // dStr2 will be “34021005323”
Then, grab the first 4 digits you are interested in
String dStr3 = dStr2.substring(0,4); // dStr3 will be “3402”
Finally, insert a decimal point
String result = dStr3.substring(0,2) + “.” + dStr3.substring(2); // result will be “34.02”
You can use format for this try this out it work 100% for me.
String.format("%.2f", value)
Helpful link
https://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html#syntax

Java Set double value with all decimal point and get only 2 digit after decimal point

In java , I have confusion about store and get double value.
Currently i am creating software where some accounting part included,i want to store calculated value same as they are calculated like 202.234234234212312 and while in display i want to display it as 202.23 in 2 digit after decimal point.
and in calculation i want to do calculation with 2,4 or 6 digit.
for that i have 2 option
Store value as it is calculated and in getter method of amount field, i can format it like.
private Double amount;
public Double getAmount() {
DecimalFormat df2 = new DecimalFormat(".##");
return Double.valueOf(df2.format(amount));
}
but problem with this method is , it will get formatted number at all time i get amount. i can't get actual stored amount.
i can use 2 separate field for get and set.
private Double amount;
private Double amountFormatted;
public Double getAmount() {
return amount;
}
public Double getAmountFormatted() {
DecimalFormat df2 = new DecimalFormat(".##");
return Double.valueOf(df2.format(amountFormatted));
}
so please provide better way to store and get decimal value, Thank you.
First of all, all calculations involving money should be done in BigDecimal, not double. A double cannot represent quantities like 0.1 exactly.
Secondly, your getAmountFormatted should not return a Double but a String if it is only intended for output purposes.
Use the same amount variable for both methods.
If I understood you correctly, you just want to get different format for same value, you can just have one variable and 2 get fields like this:
private Double amount;
public Double getAmount() {
return amount;
}
public Double getAmountFormatted() {
DecimalFormat df2 = new DecimalFormat(".##");
return Double.valueOf(df2.format(amount));
}
It's not an entity's job to provide formatted data for display: leave formatting to the code that is actually doing the displaying. More to the point, it's not your job as the programmer of the entity class to 1) anticipate every future need for a formatted value, and 2) constantly update the entity class to provide new formatted values that you didn't (nay, couldn't) anticipate.
So just have the getAmount method return the raw unadulterated data:
public class Entity {
private BigDecimal amount;
public BigDecimal getAmount(){
return amount;
}
//...
}
and eliminate getAmountFormatted from the entity. When you want to display the amount formatted to two decimal places, just obtain the raw amount with getAmount() and format it right on the spot:
Entity e = ...;
DecimalFormat df = new DecimalFormat(".##");
System.out.println("The amount is " + df.format(e.getAmount());
Here's a little story that illustrates why I think this is the way to go...
Suppose there's a second amount, otherAmount in your entity, that was included at the time the entity was created because someone thought it might be needed in the future. And suppose that, because the field had no planned use at the time, you didn't bother to create a getOtherAmountFormatted() method to provide a two-decimal-formatted version of otherAmount.
Now the future arrives. The otherAmount field is now being used, and you need to start displaying it with two decimal places along with the original amount. You know you're going to have to add the line
System.out.println("The other amount is " + ...
into the code that's displaying the amounts. Only question is, how do you finish that line. Do you add into your entity class a getOtherAmountFormatted() method and then write:
System.out.println("The other amount is " + e.getOtherAmountFormatted()); // NO!!
Or do you not touch the entity class at all and just write:
System.out.println("The other amount is " + df.format(e.getOtherAmount()); // Yes!!
The entity isn't the class that ultimately needs the formatted version of otherAmount, so it shouldn't have to change just to accommodate some entirely other bit of code that now happens to need a formatted version of otherAmount. Especially when that other bit of code can just get the unformatted amount, which the unmodified entity can already provide, and then do the needed formatting for itself.
Next scenario: in the further future, yet another requirement has come up to print those amount fields, but now with with three decimal places. Are you going to add yet more methods into the entity class to provide three-decimal versions of the amounts (in addition to the ones already providing two-decimal versions)? Or will you not touch the entity class at all and just write, at the point you need those three-decimal formatted values:
DecimalFormat df3 = new DecimalFormat(".###");
// ...
System.out.println("The amount in 3 decimals is " + df3.format(e.getAmount());
System.out.println("The other amount in 3 decimals is " + df3.format(e.getOtherAmount());

Compare two large numbers

Two strings representing two numbers have been provided as input. The numbers in the string can be so large that they may not be represented by the Java data type int. The objective is to compare the two numbers and output that number as a string
for example we have to compare:
"874986754789289867753896798679854698798789857387687546456"
and
"98347598375689758967756458678976893478967586857687569874"
which both are out of range of long and int data types in JAVA
and after comparing we have to output that number as a string
you could start by first looking at each string's length. if one of them is longer and you know they are both unsigned values, the longer string has the bigger number. if they both have the same length, you start comparing the strings char by char starting from left to right. when you found your first bigger digit you conclude that number is bigger.
Whether you're trying to compare or subtract isn't clear, but Java's BigInteger class has both operations. This is probably what you need:
BigInteger a = new BigInteger("874986754789289867753896798679854698798789857387687546456");
BigInteger b = new BigInteger("98347598375689758967756458678976893478967586857687569874");
System.out.println( (a.compareTo(b) > 0 ? "a" : "b") + " is larger.");
If you need to subtract the numbers I'd definitely use BigInteger, but if all you need to do is compare them you could write your own method. One of your input strings is longer than the other, so barring leading zeroes that would tell you right away which is larger. If the strings are the same length you could compare them character by character in a loop to see which is larger. The String charAt and toCharArray methods give you two different ways to implement this approach.
In order to use numbers that big, they must be declared as double. You can use parsers to transform Strings into numbers.
public static void main(String [] args) {
String numberOne = "874986754789289867753896798679854698798789857387687546456";
double parsedNumberOne = Double.parseDouble(numberOne);
String numberTwo = "98347598375689758967756458678976893478967586857687569874";
double parsedNumberTwo = Double.parseDouble(numberTwo);
double result = compareMethod (numberOne, numberTwo);
System.out.println("Result = " + result);
}
I declared the numbers explicitly and not by reading user input, but you can modify that easily to be inline with your code. In the compareMethod, you can compare those number anyway you like.
Regards
Just comparing two strings using compareTo() is more than enough. The comparison will be done by converting each character into its ASCII value.
String number1 = "874986754789289867753896798679854698798789857387687546457";
String number2 = "874986754789289867753896798679854698798789857387687546456";
int result = number1.compareTo(number2);
if (result == 0) {
System.out.println("Both are equal");
} else if (result > 0) {
System.out.println("Number1 is greater");
} else {
System.out.println("Number2 is greater");
}
If it is school assignment in which you can't use built-in solutions but you need to write your own method to compare such strings then you need to
check sign of numbers (if one is negative and one positive then answer is obvious)
remove leading zeroes - 0000123 represents 123
after removing leading zeroes compare length of numbers (longer one among positive numbers is larger)
if both numbers have same length iterate over them from left to right until you will find two different digits (if you will not find any numbers are equal).
Members of String class you may need
toCharArray()
charAt(int index)
length
In case you can use built-in solutions you can use these strings to create BigInteger instances and use its compareTo method which will tell if one number is larger (positive result) equal to (0) or smaller (negative result) than other.
You need to compare characters (converted to numbers) one by one (or group by group) from right to left. Use methods like charAt(int) or substring(int, int) respectively.

Converting non-numeric String to Integer?

How can I convert a non-numeric String to an Integer?
I got for instance:
String unique = "FUBAR";
What's a good way to represent the String as an Integer with no collisions e.g. "FUBAR" should always be represented as the same number and shan't collide with any other String. For instance, String a = "A"; should be represented as the Integer 1 and so on, but what is a method that does this (preferrably for all unicode strings, but in my case ASCII values could be sufficient).
This is impossible. Think about it, an Integer can only be 32 bits. So, by the pigeonhole principle, there must exist at least two strings that have the same Integer value no matter what technique you use for conversion. In reality, there are infinite with the same values...
If you're just looking for an efficient mapping, then I suggest that you just use the int returned by hashCode(), which for reference is actually 31 bits.
You can map Strings to unique IDs using table. There is not way to do this generically.
final Map<String, Integer> map = new HashMap<>();
public int idFor(String s) {
Integer id = map.get(s);
if (id == null)
map.put(s, id = map.size());
return id;
}
Note: having unique id's doesn't guarantee no collisions in a hash collection.
http://vanillajava.blogspot.co.uk/2013/10/unique-hashcodes-is-not-enough-to-avoid.html
If you know the character set used in your strings, then you can think of the string as number with base other than 10. For example, hexadecimal numbers contain letters from A to F.
Therefore, if you know that your strings only contain letters from an 8-bit character set, you can treat the string as a 256-base number. In pseudo code this would be:
number n;
for each letter in string
n = 256 * n + (letter's position in character set)
If your character set contains 65535 characters, then just multiply 'n' with that number on each step. But beware, the 32 bits of an integer will be easily overflown. You probably need to use a type that can hold a larger number.
private BigDecimal createBigDecimalFromString(String data)
{
BigDecimal value = BigDecimal.ZERO;
try
{
byte[] tmp = data.getBytes("UTF-8");
int numBytes = tmp.length;
for(int i = numBytes - 1; i >= 0; i--)
{
BigDecimal exponent = new BigDecimal(256).pow(i);
value = value.add(exponent.multiply(new BigDecimal(tmp[i])));
}
}
catch (UnsupportedEncodingException e)
{
}
return value;
}
Maybe a little bit late, but I'm going to give my 10 cents to simplify it (internally is similar to BigDecimal suggested by #Romain Hippeau)
public static BigInteger getNumberId(final String value) {
return new BigInteger(value.getBytes(Charset.availableCharsets().get("UTF-8")));
}
Regardless of the accepted answer, it is possible to represent any String as an Integer by computing that String's Gödelnumber, which is a unique product of prime numbers for every possible String. With that being said it's quite impractical and slow to implement, also for most Strings you would need a BigInteger rather than a normal Integer and to decode a Gödelnumber into its corresponding String you need to have a defined Charset.

How to always round in two decimals

For a project at school, I have to make a java program to retrieve data from a database.
This is my code:
import java.text.*;
import java.util.*;
public class Tijdstip
{
public Tijdstip()
{
}
public double testTijd(String tijdstip1)
{
// splitting the time
String[] tokens = tijdstip1.split("\\s+");
int hours = Integer.parseInt(tokens[0]);
int minutes = Integer.parseInt(tokens[1]);
//returning the time
double result = hours + ((double)minutes/100);
return result;
}
}
I fill in a time as string like: "7 10", meaning 7:10am and it must return a double like 7.10
But it returns 7.1, how do I make it so it will return 7.10 instead of 7.1?
You need to understand the difference between how a number is represented and how it is displayed. There is no numeric difference between 7.1 and 7.10; there is no way to make the number one instead of the other. You can display 7.1 as 7.10 using output formatting such as found in the Format class.
As a side issue: Storing this as a double would be a bad idea in a program of any size. There are many classes for representing time, and they all take into account the non-decimal nature of time divisions. Doubles don't do this.
Try this
new DecimalFormat("#.00").format(result);
The short answer is that you cannot do this if you must keep the result as a double. The double doesn't know anything about leading or trailing zeros. You can only do this when the result is formatted as a String. E.g., String.format("%.2f", 7.1) gives the string "7.10". You can easily do this formatting every time you display the number, but you cannot make the number itself remember the extra zero.
When you return double it will always truncate your last number if it is zero. so make it a string and return
If you need double value which has only two digits after dicimal, you can try following:
double d = 1.164444;
double r = Math.rint(d * 100)/100;
System.out.println(r);

Categories

Resources