How can I represent a range in Java?
Let’s say an integer should be within the range: [0. 2147483647] I want to check whether an integer variable falls within this range. I know it can be accomplished by a simple if-else statement, but is there a more efficient way to check whether it’s within the range? I’d rather not do this:
If you’re asking for runtime efficiency (performance), I’m afraid that your if statement wins. I agree, though, that this observation shouldn’t drive your decision. For 99 % of applications, maintenance efficiency will be more important.
@OleV.V. I’d even simplify it to if(foo >= 0) … , as there’s no need to check whether an int is
@OleV.V., Care has to be taken in how often and in what way this is called. Pipelining becomes 100% squashed on conditionals. If you can enforce a clamped range through some other «solid state» mathematical wizardry, then you’ll be better off.
9 Answers 9
Apache Commons Lang has a Range class for doing arbitrary ranges.
Range test = Range.between(1, 3); System.out.println(test.contains(2)); System.out.println(test.contains(4));
If you are just wanting to check if a number fits into a long value or an int value, you could try using it through BigDecimal . There are methods for longValueExact and intValueExact that throw exceptions if the value is too big for those precisions.
Answer my own question. «Yes» is the answer. See : Range.atMost and Range.atLeast. guava.dev/releases/snapshot/api/docs/com/google/common/collect/…
The problem with this Range is that it seems to be missing something akin to an addWrap() and subtractWrap() concepts, both of which are very useful when you need to dec/subtracting downward a value below minimum to wrap to max and similar for inc/adding a value to wrap when past max. You could even use the % if required and allow floating point. These are very easy to implement on your own, but they really should at least be Math methods IMO to take advantage of any native-level atomic operations that may be present.
You could create a class to represent this
public class Range < private int low; private int high; public Range(int low, int high)< this.low = low; this.high = high; >public boolean contains(int number)< return (number >= low && number >
Range range = new Range(0, 2147483647); if (range.contains(foo)) < //do something >
I now see you were trying to avoid the if. I thought you just didn’t like the comparison syntax in the if. oh well.
With this implementation, you cannot represent an empty range (assuming low
I know this is quite an old question, but with Java 8’s Streams you can get a range of int s like this:
// gives an IntStream of integers from 0 through Integer.MAX_VALUE IntStream.rangeClosed(0, Integer.MAX_VALUE);
Then you can do something like this:
if (IntStream.rangeClosed(0, Integer.MAX_VALUE).matchAny(n -> n == A)) < // do something >else < // do something else >
@Michael up to 2 billion comparisons, but only A in the best case. On the other hand, you need only one actual comparison, A >= 0 here.
You could use java.time.temporal.ValueRange which accepts long and would also work with int :
int a = 2147; //Use java 8 java.time.temporal.ValueRange. The range defined //is inclusive of both min and max ValueRange range = ValueRange.of(0, 2147483647); if(range.isValidValue(a)) < System.out.println("in range"); >else
If you are checking against a lot of intervals, I suggest using an interval tree.
You will have an if-check no matter how efficient you try to optimize this not-so-intensive computation 🙂 You can subtract the upper bound from the number and if it’s positive you know you are out of range. You can perhaps perform some boolean bit-shift logic to figure it out and you can even use Fermat’s theorem if you want (kidding 🙂 But the point is «why» do you need to optimize this comparison? What’s the purpose?
I’m with the OP — this kind of procedural check has always felt awkward. I prefer declarative contracts when available, even if the former eventually reduces to the latter.
I need to optimize because I find it much slower when let’s say A is a really big number. And what if I choose to expand and do other checks within that if..else statement? >_
For a range of Comparable I use the following :
public class Range> < /** * Include start, end in */ public enum Inclusive /** * start and end values */ private T start, end; private Inclusive inclusive; /** * Create a range with * @param start *
Not null safe * @param end *
Not null safe */ public Range(T start, T end) < this(start, end, null); >/** * @param start *
Not null safe * @param end *
Not null safe *@param inclusive *
If null used */ public Range(T start, T end, Inclusive inclusive) < if((start == null) || (end == null)) < throw new NullPointerException("Invalid null start / end value"); >setInclusive(inclusive); if( isBigger(start, end) ) < this.start = end; this.end = start; >else < this.start = start; this.end = end; >> /** * Convenience method */ public boolean isBigger(T t1, T t2) < return t1.compareTo(t2) >0; > /** * Convenience method */ public boolean isSmaller(T t1, T t2) < return t1.compareTo(t2) < 0; >/** * Check if this contains t *@param t *
Not null safe *@return *false for any value of t, if this.start equals this.end */ public boolean contains(T t) < return contains(t, inclusive); >/** * Check if this contains t *@param t *
Not null safe *@param inclusive *
If null used *@return *false for any value of t, if this.start equals this.end */ public boolean contains(T t, Inclusive inclusive) < if(t == null) < throw new NullPointerException("Invalid null value"); >inclusive = (inclusive == null) ? this.inclusive : inclusive; switch (inclusive) < case NONE: return ( isBigger(t, start) && isSmaller(t, end) ); case BOTH: return ( ! isBigger(start, t) && ! isBigger(t, end) ) ; case START: default: return ( ! isBigger(start, t) && isBigger(end, t) ) ; case END: return ( isBigger(t, start) && ! isBigger(t, end) ) ; >> /** * Check if this contains other range * @return * false for any value of range, if this.start equals this.end */ public boolean contains(Range range) < return contains(range.start) && contains(range.end); >/** * Check if this intersects with other range * @return * false for any value of range, if this.start equals this.end */ public boolean intersects(Range range) < return contains(range.start) || contains(range.end); >/** * Get */ public T getStart() < return start; >/** * Set *
Not null safe *
If start > end they are switched */ public Range setStart(T start) < if(start.compareTo(end)>0) < this.start = end; this.end = start; >else < this.start = start; >return this; > /** * Get */ public T getEnd() < return end; >/** * Set *
Not null safe *
If start > end they are switched */ public Range setEnd(T end) < if(start.compareTo(end)>0) < this.end = start; this.start = end; >else < this.end = end; >return this; > /** * Get */ public Inclusive getInclusive() < return inclusive; >/** * Set * @param inclusive *
If null used */ public Range setInclusive(Inclusive inclusive) < this.inclusive = (inclusive == null) ? Inclusive.START : inclusive; return this; >>
(This is a somewhat shorted version. The full code is available here )
Java Program to Generate Range of Numbers
Java Program to Generate Range Numbers using for loop
In java programming, this program is used to display the integer numbers from range format user input.
Suppose user gives the input 10-15, then this program generates the numbers from 10 to 15 (10, 11, 12, 13, 14, 15).
import java.util.Scanner; public class RangeNumbers < public static void main(String[] args)< System.out.print("Enter Range (Ex: 10-15): "); Scanner sc=new Scanner(System.in); String strRange = sc.nextLine(); String[] strRangeValues = strRange.split("-"); int min=0,max=0; if(strRangeValues.length==2)< min = Integer.parseInt(strRangeValues[0].trim()); max = Integer.parseInt(strRangeValues[1].trim()); if(min<=max)< System.out.println("Range Numbers"); for(int i=min;i<=max;i++)< System.out.print(i+ " "); >System.out.println(); > else < System.out.println("Invalid range!"); >> else < System.out.println("Invalid range!"); >> >
D:\Java_Programs>javac RangeNumbers.java D:\Java_Programs>java RangeNumbers Enter Range (Ex: 10-15): 11-19 Range Numbers 11 12 13 14 15 16 17 18 19 D:\Java_Programs>javac RangeNumbers.java D:\Java_Programs>java RangeNumbers Enter Range (Ex: 10-15): 14-10 Invalid range!
Java Program to Generate Range Numbers using while loop
import java.util.Scanner; public class RangeNumbers < public static void main(String[] args)< System.out.print("Enter Range (Ex: 10-15): "); Scanner sc=new Scanner(System.in); String strRange = sc.nextLine(); String[] strRangeValues = strRange.split("-"); int min=0,max=0; if(strRangeValues.length==2)< min = Integer.parseInt(strRangeValues[0].trim()); max = Integer.parseInt(strRangeValues[1].trim()); if(min<=max)< System.out.println("Range Numbers"); int i=min; while(i<=max)< System.out.print(i+ " "); i++; >System.out.println(); > else < System.out.println("Invalid range!"); >> else < System.out.println("Invalid range!"); >> >
D:\Java_Programs>javac RangeNumbers.java D:\Java_Programs>java RangeNumbers Enter Range (Ex: 10-15): 12-16 Range Numbers 12 13 14 15 16 D:\Java_Programs>javac RangeNumbers.java D:\Java_Programs>java RangeNumbers Enter Range (Ex: 10-15): 14-10 Invalid range!
Difference between Scanner next and nextLine methods
next method is used to read the string till space or line end but when use nextLine method reads the string till end of line.
Example 10 — 11 entered by user, next method reads only 10 but nextLine method reads the string 10 — 11.
For loop — like Python range function
This was an easy way to make for enhanced loops. It would be great to do this in Java because it would make for loops a lot easier. Is this possible?
9 Answers 9
Java 8 (2014) has added IntStream (similar to apache commons IntRange), so you don’t need external lib now.
import java.util.stream.IntStream; IntStream.range(0, 3).forEachOrdered(n -> < System.out.println(n); >);
forEach can be used in place of forEachOrdered too if order is not important.
IntStream.range(0, 3).parallel() can be used for loops to run in parallel
Without an external library, you can do the following. It will consume significantly less memory for big ranges than the current accepted answer, as there is no array created.
class Range implements Iterable < private int limit; public Range(int limit) < this.limit = limit; >@Override public Iterator iterator() < final int max = limit; return new Iterator() < private int current = 0; @Override public boolean hasNext() < return current < max; >@Override public Integer next() < if (hasNext()) < return current++; >else < throw new NoSuchElementException("Range reached the end"); >> @Override public void remove() < throw new UnsupportedOperationException("Can't remove values from a Range"); >>; > >
and you can simply use it like this:
Range range5 = new Range(5); for (int i : range5) < System.out.println(i); >for (int i : range5)
As Henry Keiter pointed out in the comment below, we could add following method to the Range class (or anywhere else):
public static Range range(int max)
and then, in the other classes we can
import static package.name.Range.range;