This commit is contained in:
@hangga 2023-11-01 10:37:14 +07:00
parent ece5cdeb6e
commit b55db89b5f
3 changed files with 73 additions and 72 deletions

View File

@ -3,17 +3,21 @@ package com.baeldung.uuid;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.UUID; import java.util.UUID;
public class UUIDLongGenerator { /**
* Methods are called by reflection in the unit test
*/
@SuppressWarnings("unused")
public class UUIDPositiveLongGenerator {
public long getLeastSignificantBits(){ public long getLeastSignificantBits(){
return UUID.randomUUID().getLeastSignificantBits(); return Math.abs(UUID.randomUUID().getLeastSignificantBits());
} }
public long getMostSignificantBits(){ public long getMostSignificantBits(){
return UUID.randomUUID().getMostSignificantBits(); return Math.abs(UUID.randomUUID().getMostSignificantBits());
} }
public long gethashCode(){ public long gethashCode(){
return UUID.randomUUID().toString().hashCode(); return Math.abs(UUID.randomUUID().toString().hashCode());
} }
public long combineByteBuffer(){ public long combineByteBuffer(){
@ -21,21 +25,21 @@ public class UUIDLongGenerator {
ByteBuffer bb = ByteBuffer.wrap(new byte[16]); ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(uuid.getMostSignificantBits()); bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits()); bb.putLong(uuid.getLeastSignificantBits());
bb.rewind(); // Kembalikan posisi buffer ke awal bb.rewind();
return bb.getLong(); return Math.abs(bb.getLong());
} }
public long combineBitwise(){ public long combineBitwise(){
UUID uniqueUUID; UUID uniqueUUID;
uniqueUUID = UUID.randomUUID(); uniqueUUID = UUID.randomUUID();
return (uniqueUUID.getMostSignificantBits() << 32) | (uniqueUUID.getLeastSignificantBits() & 0xFFFFFFFFL); return Math.abs((uniqueUUID.getMostSignificantBits() << 32) | (uniqueUUID.getLeastSignificantBits() & 0xFFFFFFFFL));
} }
public long combineDirect(){ public long combineDirect(){
UUID uniqueUUID = UUID.randomUUID(); UUID uniqueUUID = UUID.randomUUID();
long mostSignificantBits = uniqueUUID.getMostSignificantBits(); long mostSignificantBits = uniqueUUID.getMostSignificantBits();
long leastSignificantBits = uniqueUUID.getLeastSignificantBits(); long leastSignificantBits = uniqueUUID.getLeastSignificantBits();
return mostSignificantBits ^ (leastSignificantBits >> 1); return Math.abs(mostSignificantBits ^ (leastSignificantBits >> 1));
} }
public long combinePermutation(){ public long combinePermutation(){
@ -53,6 +57,6 @@ public class UUIDLongGenerator {
for (byte b : uuidBytes) { for (byte b : uuidBytes) {
result = (result << 8) | (b & 0xFF); result = (result << 8) | (b & 0xFF);
} }
return result; return Math.abs(result);
} }
} }

View File

@ -1,63 +0,0 @@
package com.baeldung.uuid;
import org.junit.jupiter.api.Test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.DecimalFormat;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class UUIDLongGeneratorUnitTest {
final static int n = 1000000;
UUIDLongGenerator uuidLongGenerator = new UUIDLongGenerator();
@Test
void whenForeachGenerateLongValue_thenCollisionsCheck() {
printTableHeader();
for (Method method : uuidLongGenerator.getClass().getDeclaredMethods()) {
collisionAndNegativeCheck(method);
}
}
private void printTableHeader() {
System.out.format("%-30s %-15s %-15s %-15s %-15s%n", "Approach", "collisions", "negatives", "collision", "negative");
System.out.format("%-30s %-15s %-15s %-15s %-15s%n", "(method name)", "count", "count", "probability", "probability");
System.out.println("--------------------------------------------------------------------------------------------");
}
private void printOutput(String method, int collisionsCount, int negativeCount, double collisionsProbability, double negativeProbability) {
DecimalFormat decimalFormat = new DecimalFormat("#.#####");
System.out.format("%-30s %-15s %-15s %-15s %-15s%n", method, collisionsCount, negativeCount, decimalFormat.format(collisionsProbability), decimalFormat.format(negativeProbability));
}
private void collisionAndNegativeCheck(Method method) {
Set<Long> uniqueValues = new HashSet<>();
AtomicInteger collisions = new AtomicInteger(0);
AtomicInteger negative = new AtomicInteger(0);
IntStream.range(0, n).forEach(i -> {
try {
long uniqueValue = (long) method.invoke(uuidLongGenerator);
if (!uniqueValues.add(uniqueValue)) {
collisions.incrementAndGet();
}
if (uniqueValue < 0) {
negative.incrementAndGet();
}
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
});
double collisionsProbability = (double) collisions.get() / n;
double negativeProbability = (double) negative.get() / n;
printOutput(method.getName(), collisions.get(), negative.get(), collisionsProbability, negativeProbability);
assertTrue(collisionsProbability <= 0.001); // threshold = 0.001
}
}

View File

@ -0,0 +1,60 @@
package com.baeldung.uuid;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.DecimalFormat;
import java.util.HashSet;
import java.util.Set;
import static org.assertj.core.api.Assertions.assertThat;
public class UUIDPositiveLongGeneratorUnitTest {
private final static int n = 1000000;
private final UUIDPositiveLongGenerator uuidLongGenerator = new UUIDPositiveLongGenerator();
private final Logger logger = LoggerFactory.getLogger(UUIDPositiveLongGeneratorUnitTest.class);
@Test
void whenForeachGenerateLongValue_thenCollisionsCheck() throws InvocationTargetException, IllegalAccessException {
printTableHeader();
for (Method method : uuidLongGenerator.getClass().getDeclaredMethods()) {
collisionAndNegativeCheck(method);
}
}
private void printTableHeader() {
logger.info(String.format("%-30s %-15s %-15s %-15s %-15s", "Approach", "collisions", "negatives", "collision", "negative"));
logger.info(String.format("%-30s %-15s %-15s %-15s %-15s", "(method name)", "count", "count", "probability", "probability"));
logger.info("--------------------------------------------------------------------------------------------");
}
private void printOutput(String method, int collisionsCount, int negativeCount, double collisionsProbability, double negativeProbability) {
DecimalFormat decimalFormat = new DecimalFormat("#.#####");
//logger.info(String.format("%-30s %-15s %-15s %-15s %-15s", method, collisionsCount, negativeCount, decimalFormat.format(collisionsProbability), decimalFormat.format(negativeProbability)));
logger.info("%-30s{} %-15s{} %-15s{} %-15s{} %-15s{}", method, collisionsCount, negativeCount, decimalFormat.format(collisionsProbability), decimalFormat.format(negativeProbability));
}
private void collisionAndNegativeCheck(Method method) throws InvocationTargetException, IllegalAccessException {
Set<Long> uniqueValues = new HashSet<>();
int collisions = 0;
int negative = 0;
for (int i = 0; i < n; i++) {
long uniqueValue = (long) method.invoke(uuidLongGenerator);
if (!uniqueValues.add(uniqueValue)) {
collisions++;
}
if (uniqueValue < 0) {
negative++;
}
}
double collisionsProbability = (double) collisions / n;
double negativeProbability = (double) negative / n;
printOutput(method.getName(), collisions, negative, collisionsProbability, negativeProbability);
assertThat(collisionsProbability).isLessThan(0.001);
}
}