Reputation: 23587
i was working on an application where we need to generate some unique number and practically there was no predefined restrictions so was using java UUD generator and was working fine. Now we are given a new requirements to generate 12 digits unique random number.
Can any one point me some good way/algorithm to achieve this as i can not see any possibility in the UUID generated number.
Thanks in advance
Upvotes: 17
Views: 61981
Reputation: 1974
I had similar issue (16 digits in my case) and didn't found a good solution so i created one here
This utility works like clock, so you get unique random numbers per installation. we generate 16 digit integer value for example 2226015501234239
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
public class App {
private Set set = new HashSet<BigInteger>();
private String flag = mostSignificantCounter();
private String mostSignificantCounter() {
LocalDateTime localDateTime = LocalDateTime.now();
return new StringBuilder()
.append((localDateTime.getYear() + "").substring(2))
.append(localDateTime.getDayOfYear())
.append(localDateTime.getHour())
.append(localDateTime.getMinute())
.append(localDateTime.getSecond())
.toString();
}
private String leastSignificantCounter() {
Random random = new Random(LocalDateTime.now().getNano());
Integer rId = (1 + random.nextInt(10) * 10000) + random.nextInt(10000);
return String.format("%05d", rId);
}
public BigInteger uniqueRandomBigInt() {
String msc = mostSignificantCounter();
BigInteger uniqueBigIntId = new BigInteger(msc + leastSignificantCounter());
if (set.contains(uniqueBigIntId)) {
return uniqueRandomBigInt();
} else {
if (!flag.equals(msc)) {
set.clear();
flag = msc;
}
set.add(uniqueBigIntId);
return uniqueBigIntId;
}
}
}
@Test
public void testApp() {
Long startTime = System.currentTimeMillis();
App app = new App();
while ((System.currentTimeMillis() - startTime) < (1000 * 60)) {
BigInteger uniqueRandomBigInt = app.uniqueRandomBigInt();
assertFalse(
testSet.contains(uniqueRandomBigInt),
"Failed to generate unique random ID, found duplicate -> " + uniqueRandomBigInt
);
testSet.add(uniqueRandomBigInt);
}
assertTrue(true);
}
Upvotes: 0
Reputation: 9
You can simply use
Random generator = new Random(System.currentTimeMillis());
return generator.nextLong() % 1000000000000;
This will limit the result to 12 digits.
Upvotes: 0
Reputation: 21
The below is the best solution,I have written after tried multiple combination . The below is the 12 digit unique Id....for every call & multiple threads also will return unique id .
Thanks CH.K M V Prasad*
private static int counter=0;
private static int oldMinute=-1;
private static int minIncr=0;
private static String repeatNumber(String repeatString ,int numberOftimes) {
String returnStr="";
for(int indexCounter=0;indexCounter<numberOftimes;indexCounter++) {
returnStr+=repeatString;
}
return returnStr;
}
public synchronized static String getUniqueID() {
System.out.println("curr Mill "+System.currentTimeMillis()+"D:"+(2020%1000)+"-"+(2021));
Calendar cal = Calendar.getInstance();
if(oldMinute==-1 || oldMinute< cal.get(Calendar.MINUTE) ) {
oldMinute=cal.get(Calendar.MINUTE);
minIncr=0;
counter=0;
}else if(counter==99) {
System.out.println("99 counter ");
oldMinute=cal.get(Calendar.MINUTE)+(++minIncr);
counter=0;
}
String uId=cal.get(Calendar.HOUR_OF_DAY)+""+cal.get(Calendar.MONTH)+""+(cal.get(Calendar.YEAR)%100)+""+oldMinute+""+cal.get(Calendar.DATE);
String incrCounter=""+(++counter);
int appendZeros=uId.length()+incrCounter.length();
System.out.println("Uid="+uId+",incrCounter="+incrCounter+" , tolalZero="+appendZeros);
return uId+repeatNumber("0", 12-appendZeros)+incrCounter;
}
Upvotes: 0
Reputation: 1
long number = 0l;
Random rand = new Random();
number = (rand.nextInt(1000000)+1000000000l) * (rand.nextInt(900)+100);
Upvotes: -2
Reputation: 101
Improved checked solution using StringBuilder():
public static long generateRandom() {
Random random = new Random();
StringBuilder sb = new StringBuilder();
// first not 0 digit
sb.append(random.nextInt(9) + 1);
// rest of 11 digits
for (int i = 0; i < 11; i++) {
sb.append(random.nextInt(10));
}
return Long.valueOf(sb.toString()).longValue();
}
Upvotes: 2
Reputation: 274878
Generate each digit by calling random.nextInt
. For uniqueness, you can keep track of the random numbers you have used so far by keeping them in a set and checking if the set contains the number you generate each time.
public static long generateRandom(int length) {
Random random = new Random();
char[] digits = new char[length];
digits[0] = (char) (random.nextInt(9) + '1');
for (int i = 1; i < length; i++) {
digits[i] = (char) (random.nextInt(10) + '0');
}
return Long.parseLong(new String(digits));
}
Upvotes: 34
Reputation: 10497
I had a very similar requirement lately and came up with this:
import com.google.inject.Provider;
import java.security.SecureRandom;
import org.apache.commons.codec.binary.Base64;
public final class SecureKeyProvider {
private final SecureRandom rng;
private final int entropyBytes;
public SecureKeyProvider(int entropyBytes) {
this.rng = new SecureRandom();
this.entropyBytes = entropyBytes;
}
public String get() {
/* SecureRandom documentation does not state if it's thread-safe,
* therefore we do our own synchronization. see
*
* http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6498354
*/
synchronized (this.rng) {
final byte[] random = new byte[this.entropyBytes];
rng.nextBytes(random);
return Base64.encodeBase64URLSafeString(random);
}
}
}
It uses the Base64 encoder from apache commons which I had in my project anyway. Maybe you want to replace it with something simple, but otherwise it does the job.
Upvotes: 1
Reputation: 1537
You could try getting the UUIDs LSB and MSB halves as longs, and convert that to a number.
Upvotes: 0
Reputation: 55886
(long)Math.random()*1000000000000L
But there are chances of collision
Why not use sequence? Starting from 100,000,000,000 to 999,999,999,999? keep a record of last generated number.
Edit: thanks to bence olah, I fixed a creepy mistake
Upvotes: 3
Reputation: 9914
You can try like this.This is generating random number for 12 digits.you have to mention the ranges.
package test;
import java.util.Random;
/** Generate random integers in a certain range. */
public final class RandomRange {
public static final void main(String... aArgs){
log("Generating random integers in the range 100000000000..999999999999.");
long START = 100000000000l;
long END = 999999999999l;
Random random = new Random();
for (int idx = 1; idx <= 10; ++idx){
showRandomInteger(START, END, random);
}
log("Done.");
}
private static void showRandomInteger(long aStart, long aEnd, Random aRandom){
if ( aStart > aEnd ) {
throw new IllegalArgumentException("Start cannot exceed End.");
}
//get the range, casting to long to avoid overflow problems
long range = (long)aEnd - (long)aStart + 1;
// compute a fraction of the range, 0 <= frac < range
long randomNumber = (long)(range * aRandom.nextDouble());
System.out.println(" fraction... "+randomNumber);
}
private static void log(String aMessage){
System.out.println(aMessage);
}
}
Upvotes: 0
Reputation: 684
Random random = new Random();
Math.round(random.nextFloat() * Math.pow(10,12))
Upvotes: 1
Reputation: 4316
I would consider a simple hashing of System.nanoTime() assuming you don't mind the 1 out of 1 billion chance of hash collision.
Upvotes: -1