Related
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? 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.
Anyway, every BigInteger (the ones that are not returned) will be garbage collected. 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. Maybe the compiler or the JVM will do this on its own.
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. (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)
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 :)
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>.
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:
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
If our numbers length == int max length : Check is it INT or LONG
If our numbers length > int max length :
3.1 If our numbers length < long max length : IT IS LONG
3.2 If our numbers length == long max length : Check is it LONG or BIG INTEGER
3.3 If our numbers length > long max length : IT IS BIG INTEGER
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.
i'm getting lost, could someone of you please help me?
i want my function "oddEvenRow" to check if the values in row index 0,2,4 are odd. if so return true, if not return false
this is the code i wrote :
public class Matrix
{
public static int temp=0;
public static boolean oddEvenRow (int[][]a, int r, int c, int count)
{
if(r>4&&count==12) {
temp=1;
return false;
}
if(a[r][c]%2==0) {
temp=1;
return false;
}
else {
count++;
if(c==3)
oddEvenRow(a,r+2,0,count);
else
oddEvenRow(a,r,c+1,count);
return true;
}
}
public static void main(String args[])
{
int r=0;
int c=0;
int count=0;
int[][]a=new int[5][4];
a[0][0]=1;
a[0][1]=3;
a[0][2]=7;
a[0][3]=15;
a[1][0]=4;
a[1][1]=15;
a[1][2]=2;
a[1][3]=9;
a[2][0]=11;
a[2][1]=21;
a[2][2]=1;
a[2][3]=45;
a[3][0]=8;
a[3][1]=15;
a[3][2]=8;
a[3][3]=12;
a[4][0]=7;
a[4][1]=3;
a[4][2]=25;
a[4][3]=21;
System.out.println(oddEvenRow(a,r,c,count));
}
}
[Looking at your code, i suspect you meant your question to say "if ALL values in rows 0,2, and 4 are odd..."]
Anyway, you're setting the short circuit variable 'temp' but never using it. Try adding a check to the top of your function...
if(temp == 1)
return false;
For me the part with count is redundant as you are checking all rows in r variable - after the last significant row (4th) the method will return. You do not need checking if there were 12 numbers checked.
What is more temp variable acts as return value in your code which you are actually returning with the method itself - also redundant.
I do not see the point in checking already defined number of values using recursion but if you need so consider the following:
public static boolean oddRow(int[][] a, int r, int c) {
//checking if we checked all rows
if (r > 4) {
return true;
}
//checking if all columns in row were checked and moving to r+2 row
if (c > 3) {
return oddRow(a, r + 2, 0);
}
//checking if current value is odd - if yes, keep checking the rest / if not, return false
return (a[r][c] % 2 == 0) ? oddRow(a, r, c + 1) : false;
}
I want to display an error if more than one of the four variables is set...
In Java..this is what I came up with..
if( (isAset() && isBset()) || (isBset() && isCset()) || (isCset() && isDset()) || (isDset() && isAset()) )
attri.greedySelectionException(..);
I wanted to check if there is a better way of doing this..?
How about you use a counter and then compare it to 1?
Something like...
int i = 0;
if (isAset()) i++;
if (isBset()) i++;
if (isCset()) i++;
if (isDset()) i++;
if (i > 1)
...
Alternatively, if you are checking properties of a certain object, you could use some reflection to iterate through the relevant properties instead of having one if statement per property.
Edit: Take a look at Marius Žilėnas's varargs static method below for some tidier code, i.e. using (changed the oldschool for to a for-each and the ternary expression for an if):
static int trueCount(boolean... booleans) {
int sum = 0;
for (boolean b : booleans) {
if (b) {
sum++;
}
}
return sum;
}
instead of several if statements.
You can simplify this expression with :
if((isAset() || isCset()) && (isBset() || isDset()))
attri.greedySelectionException(..);
Wolfram alpha made the work for you :
Original expression
You can verify with the truth tables :
Original
Final
In Java 8 you can solve this problem with Streams in an elegant way (assuming your values are null if they are not set):
if (Stream.of(valueA, valueB, valueC, valueD).filter(Objects::nonNull).count() != 1) {
/* throw error */
}
If you have control on the implementation of isAset(), isBSet, isCSet, & isDset methods, you can achieve this with much more clarity if you return 1 or 0 instead of true or fales from this functions. These functions are to be created as below...
public int isAset()
{
return (A != null) ? 1 : 0;
}
To verify if more than one variable is set use use something like below...
if( isASet() + isBSet() + isCSet() + isDSet() > 1)
ThrowMoreAreSetException()
If you don't have control on this here is another way of doing it...
int count = isASet() ? 1 : 0;
count+= isBSet() ? 1 : 0;
count+= isCSet() ? 1 : 0;
count+= isDSet() ? 1 : 0;
if(count > 1)
ThrowMoreAreSetException()
By following either of these approches, code will be less clumsy and more readable than doing somany comparision combinations.
I suggest using varargs ... (see Java tutorial) and make a function that calculates how many trues was given. The following code to demonstrates it:
public class Values
{
public static boolean isASet()
{
return false;
}
public static boolean isBSet()
{
return true;
}
public static boolean isCSet()
{
return true;
}
public static boolean isDSet()
{
return true;
}
public static int booleans(boolean... booleans)
{
int sum = 0;
for (int i = 0; i < booleans.length; i++)
{
sum += booleans[i] ? 1 : 0;
}
return sum;
}
public static void main(String[] args)
{
System.out.println(
booleans(isASet(), isBSet(), isCSet(), isDSet()));
if (1 < booleans(isASet(), isBSet(), isCSet(), isDSet()))
{
System.out.println("Condition met.");
}
}
}
Try this:
if (!(isAset ^ isBset ^ isCset ^ isDset))
This will true only is any one is true or else false.
I'm trying to write a test case where my scenario is that two byte arrays should be not equal.
Can I do this with junit?
Or do I have to use something external like Hamcrest? I couldn't change the code in this answer to do the job
Please give a sample.
You can use
assertFalse(Arrays.equals(array1, array2));
If you wanted to check they were equal, I would use the following instead.
assertEquals(Arrays.toString(array1), Arrays.toString(array2));
as this produces a readable output as to what was different rather than just failing.
I prefer doing this the Hamcrest way, which is more expressive:
Assert.assertThat(array1, IsNot.not(IsEqual.equalTo(array2)));
Or the short version with static imports:
assertThat(array1, not(equalTo(array2)));
(The IsEqual matcher is smart enough to understand arrays, fortunately.)
Note that a limited version of Hamcrest is part of the JUnit 4.x distribution, so you don't need to add an external library.
Newer versions of JUnit offer org.junit.Assert.assertArrayEquals(byte[], byte[]), with overloads for other array types. Failures show the first index with a non-match and the differing elements at that index.
I also enjoy assertEquals(Arrays.asList(expected), Arrays.asList(actual)). The Hamcrest-powered rendition mentioned above is probably best.
Here is a possible alternative, which has the advantage of using the same code as assertArrayEquals() :
private void assertArrayNotEquals(byte[] expecteds, byte[] actuals) {
try {
assertArrayEquals(expecteds, actuals);
} catch (AssertionError e) {
return;
}
fail("The arrays are equal");
}
You could do it like this:
assertNotEquals(arrayOne, arrayTwo)
Sorry this is a bit long but it's easy to debug with and you can cut and paste it into your unit test.
private int span = 10;
private boolean equal(byte[] expected, byte[] got) {
final boolean result;
String message = null;
int offset = -1;
int length = -1;
if(expected == null && got == null) {
result = true;
} else if(expected == null || got == null) {
message = "One array is null: " + (expected == null ? "expected" : "got");
result = false;
} else if(expected.length != got.length) {
message = "Lengths differ: expected = " + expected.length + ", got = " + got.length;
result = false;
} else {
length = expected.length;
for(int i = 0; i < length; i++) {
if(expected[i] != got[i]) {
offset = i;
break;
}
}
result = offset == -1;
if(!result) {
message = "Contents differ";
}
}
if(!result) {
System.err.println(message);
if(offset >= 0) {
hexDump("Expected: ", expected, offset, length);
hexDump(" Got: ", got, offset, length);
}
}
return result;
}
private void hexDump(String label, byte[] ba, int offset, int length) {
System.err.print(label);
if(ba == null) {
System.err.println("<null>");
} else if(ba.length == 0) {
System.err.println("<zero-length-array>");
} else {
// <span> bytes either side
final int from = Math.max(0, offset - span);
final int to = Math.min(length, offset + span);
if(from != 0) {
System.err.print("(offset:" + from + ") ");
}
for(int i = from; i < to; i++) {
System.err.printf("%02X ", new Byte(ba[i]));
}
System.err.println();
}
}
#Test
public void testExample() {
assertTrue(equal(new byte[] { 1, 2, 3 }, new byte[] { 1, 8, 3 }));
}
We have n variables X = {x1,x2,...xn} they are not in any structures whatsoever.
In python for example I can do that: if (x1 == x2 == x3 == xn):
In java I must do: if((x1 == x2) && (x2 == x3) && (x3 == xn)):
Do you know a simple way to improve this syntax? (Imagine very long variable name and lot of them)
Thanks.
If you have lots of these variables, have you considered putting them in a collection instead of having them as separate variables? There are various options at that point.
If you find yourself doing this a lot, you might want to write helper methods, possibly using varargs syntax. For example:
public static boolean areAllEqual(int... values)
{
if (values.length == 0)
{
return true; // Alternative below
}
int checkValue = values[0];
for (int i = 1; i < values.length; i++)
{
if (values[i] != checkValue)
{
return false;
}
}
return true;
}
An alternative as presented by glowcoder is to force there to be at least one value:
public static boolean areAllEqual(int checkValue, int... otherValues)
{
for (int value : otherValues)
{
if (value != checkValue)
{
return false;
}
}
return true;
}
In either case, use with:
if (HelperClass.areAllEqual(x1, x2, x3, x4, x5))
{
...
}
You could create a utility method like this:
public boolean allEqual(Object... objs) {
if(objs.length < 2) return true; // 0 or 1 objects are all equal
Object key = objs[0]; // pick one
for(Object o : objs) if(!o.equals(key)) return false;
return true;
}
Another option would be
public boolean allEqual(Object key, Object... objs) {
for(Object o : objs) if(!o.equals(key)) return false;
return true;
}
To simplify a lot of boilerplate logic. Then just go
if(allEqual(x,x1,x2,x3))
Obviously the two are mutually exclusive (they are signaturely ambigous) but you could have
allEqual and allEqualWithKey
Similar to #Jon's solution but shorter.
public static boolean areAllTheSame(int value, int... values) {
for (int i: values) if(value != i) return false;
return true;
}
You could write a method that makes this look less cumbersome:
boolean areAllEqual(Object... values) {
if (values.length < 2) {
return true;
}
for (int i = 1; i < values.length; i++) {
if (!values[i].equals(values[0])) {
return false;
}
}
return true;
}
Use it like this:
if (areAllEqual(x1, x2, x3, x4, x5)) {
// do something
}
edit Too slow...! :-(
Unfortunately, no, there's no syntactic sugar available. This is a common gripe about Java.
/*
* reference - basic String to compare against
* entries - all other objects for comparison
*/
public static boolean allEqual(String reference, String... entries) {
return Arrays.stream(entries)
.allMatch(entry -> Objects.equals(reference, entry));
}
/*
* Method can be generalized to use <T> instead of String
*/
public static <T>boolean allEqual(T reference, T... entries) {
return Arrays.stream(entries)
.allMatch(entry -> Objects.equals(reference, entry));
}
public static void main(String[] args) {
System.out.println(allEqual("X", "X", "X", "X")); // true
System.out.println(allEqual("X", "X", "Y")); // false
System.out.println(allEqual("X")); // true
System.out.println(allEqual(10, 10, 9)); // false
System.out.println(allEqual(10, 10)); // true
System.out.println(allEqual(10, new Integer[] {10, 10, 10})); // true
}
If you don't like typing, you could lose the nested paretheses:
if(x1 == x2 && x2 == x3 && x3 == xn);
Another quick way to achieve this would be via the array -> List -> HashSet conversion route, as in:
Standard Java:
if(new HashSet<Object>(Arrays.asList(x1, x2, x3, x4, x5)).size() == 1) {
}
Google Guava:
if(Sets.newHashSet(Ints.asList(x1, x2, x3, x4, x5)).size() == 1) {
}
The aforementioned solution doesn't look too clean in it's own right, though, so it should definitely be isolated into a separate utility method with a sensible name (in which case you'd probably be better off with Peter Lawrey's or Jon Skeet's solution in the first place).
I'd also expect this approach to be associated with at least a tiny performance hit, since it's clear that multiple Collections have to be instantiated & populated.
So to reiterate - only use this solution if you are hell-bent on hitting a one-liner.
In Java 8 this can be done as a one-liner using a Stream:
boolean allEqual = Stream.of(x1, x2, x3, x4).distinct().count() == 1;
Basically distinct filters the stream by checking each element for equality, so that only unique elements remain. If there is exactly one element left after filtering, it means all original elements are equal.
I like the boilerplate logic that has already been suggested, but typically any of the arguments in the list can be null, which could cause a NullPointerException to be thrown. We should therefore test for null first and use == to compare object references where appropriate:
public static boolean allEqual(Object key, Object... objs) {
for(Object o : objs)
if((key != null && !key.equals(o)) || key != o) return false;
return true;
}
org.apache.commons.lang3.BooleanUtils
public static boolean and(final boolean... array)
Just to bring these answers up to date (Java SE 9).
Set.of(x1,x2,...xn).size() == 1
Makes perfect sense to a mathematician. (I am calling myself a mathematician in this context.)
(Obviously, there are boxing overheads of one sort of another for the Integers, Integer[], Set and, potentially, internally to the Set.)
Edit: Stuart Marks points out that Set.of throws IllegalArgumentException if there are duplicate elements. Alternative:
Set.copyOf(Arrays.asList(x1,x2,...xn)).size() == 1
or depending on your definition of clean:
copyOf(asList(x1,x2,...xn)).size() == 1
(Assumes excessive static imports.)
Using the following code snipped you can identify Map values with duplicates:
public static void main(String[] args) {
int a = 1;
int b = 2;
int c = 1;
int d = 3;
Collection<Integer> collectionOfValues = List.of(a, b, c, d);
Map<Integer, List<Integer>> groupedByUniqueKeys = collectionOfValues.stream()
.collect(
groupingBy(
Function.identity()));
System.out.println(groupedByUniqueKeys);
// {1=[1, 1], 2=[2], 3=[3]}
}
The mapping for key 1 will contain values for the variables with equal values (a and c).