开发者

12 Digit unique random number generation in Java

i was working on an application where we need to generate some unique number and practically there was no predefined restric开发者_如何学Gotions 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


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));
}


(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


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();
}


Random random = new Random();
Math.round(random.nextFloat() * Math.pow(10,12))


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.


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);
  }
}


You could try getting the UUIDs LSB and MSB halves as longs, and convert that to a number.


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;

}


You can simply use

Random generator = new Random(System.currentTimeMillis());
return generator.nextLong() % 1000000000000;

This will limit the result to 12 digits.


I had similar issue (16 digits in my case) and didn't found a good solution so i created one here

Idea

This utility works like clock, so you get unique random numbers per installation. we generate 16 digit integer value for example 2226015501234239

Implementation

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;
        }
    }
}

Stress test

 @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);
    }


I would consider a simple hashing of System.nanoTime() assuming you don't mind the 1 out of 1 billion chance of hash collision.


long number = 0l;
Random rand = new Random();
number = (rand.nextInt(1000000)+1000000000l) * (rand.nextInt(900)+100);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜