Generate 16-digit unique code (like product serial) I am not sure what to call this type of code (16-digit alphanumeric code).

Conditions are like this:


Digits (or characters) are limited 16
Numeric, alphabet mixed
No duplication allowed (not yet implemented)


One class with the main method:

public class QuadraDigitCipherGenerator {
    // Step 1. Generate 16 digit wich is not duplicated
    // Step 2. divide by 4 digit

    private static List&lt;Integer&gt; pickRandomIndex (String original, int count) {
        List&lt;Integer&gt; randIndices = new ArrayList&lt;Integer&gt;();
        Set&lt;Integer&gt; noDuplicateIndices = new HashSet&lt;Integer&gt;();
        System.out.println(noDuplicateIndices.size() + "    " + count);
        while (noDuplicateIndices.size() &lt; count){
            System.out.println(noDuplicateIndices.size() + "    " + count);
            int randNumber = (int)(Math.random() * original.length());
            noDuplicateIndices.add(randNumber);
        }
        randIndices.addAll(noDuplicateIndices);
        return randIndices;
    }

    // FROM 97 - 122
    private static char convertDigit2Char(char digit) {
        return (char)(17 + digit);
    }

    private static String generateCode(int digit, int charCnt) {
        long nano = System.nanoTime();
        StringBuilder util = new StringBuilder(String.valueOf(nano));
        util = util.reverse();
        List&lt;Integer&gt; convertIndices = pickRandomIndex(util.toString(), charCnt);
        System.out.println("Below indices will be casting to Alphabet " + convertIndices);

        for(Integer i : convertIndices){
            char target = util.charAt(i);
            util.setCharAt(i, convertDigit2Char(target));
        }
        return util.toString();
    }

    private static String beautifyDigits(String original, int term){
        System.out.println("original " + original);
        return original.substring(0, term) + "-" + original.substring(term, 2*term)
                + "-" + original.substring(2*term, 3*term) + "-" + original.substring(3*term, 4*term);
    }


    public static void main(String argv[]) throws Exception {
        int digit = 16;
        System.out.println(digit + " digits random code &gt; " + beautifyDigits(generateCode(16, 4), 4));
    }
}


The output looks like D33J-H872-3545-71A1, a product serial key.  

Anyway, I think this code is not satisfied with the third condition (no duplication). Do you have any advice with regards to that aspect of the requirements?
Okay first off, let's make your random character choosing better.

The simplest way to get random symbols is to simply define the alphabet and then index into it. 

So here's how you'd typically do it:

static final private String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
final private Random rng = new SecureRandom();    

char randomChar(){
    return ALPHABET.charAt(rng.nextInt(ALPHABET.length()));
}

String randomUUID(int length, int spacing, char spacerChar){
    StringBuilder sb = new StringBuilder();
    int spacer = 0;
    while(length &gt; 0){
        if(spacer == spacing){
            sb.append(spacerChar);
            spacer = 0;
        }
        length--;
        spacer++;
        sb.append(randomChar());
    }
    return sb.toString();
}


The likelihood of generating two keys that are duplicates is  \$\frac{1}{36^{16}} \approx 8\cdot 10^{-24}\$. So if you generate 10000 (ten thousand) bulk keys, the likelyhood of not having any duplicates is: $$(1-\frac{1}{36^{16}})^{10000}=99.99999999999999999987\%$$.

In other words, you are not very likely to get duplicates as long as your random function is good (hence the use of SecureRandom instead of Math.random(). To be certain you have to always check against your database anyway as a last step so I would just not bother with duplicate checking on the client side as the likelihood of finding duplicates is so very low.