//The data to be checksumed.
final var data = "Hello";
final MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-256");
try (DigestInputStream dis = new DigestInputStream(
//This can be replaced with FileInputStream.
//The data just needs to be a File path.
new ByteArrayInputStream(data.getBytes())
, md)) {
final var buffer = new byte[4096];
int bytesRead;
while ((bytesRead = dis.read(buffer)) != -1) {
// Read the data into the buffer to update the digest
md.update(buffer, 0, bytesRead);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
final var digest = md.digest();
final var sb = new StringBuilder();
for (final byte b : digest) {
sb.append(String.format("%02x", b & 0xff));
}
System.out.println("Checksum: " + sb.toString());
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
Category: Java 17
//This will hold the target leaf certificate.
Optional<Certificate> cert;
try {
//Must hold the target URL.
final var targetUrl = "https://www.google.com";
final var httpsURL = new URL(targetUrl);
final var connection = (HttpsURLConnection) httpsURL.openConnection();
connection.connect();
//Retrieve the first certificate. This is normally the leaf certificate.
cert = Arrays.stream(connection.getServerCertificates()).findFirst();
} catch (IOException e) {
throw new RuntimeException(e);
}
cert.ifPresent(cer -> {
//Check if the instance of certificate is of type of X509Certificate.
if(cer instanceof final X509Certificate x509) {
System.out.println("Subject: " + x509.getSubjectX500Principal().getName());
System.out.println("From: " + x509.getNotBefore());
System.out.println("To: " + x509.getNotAfter());
System.out.println("Duration: " + ChronoUnit.DAYS.between(LocalDate.now(), LocalDate.ofInstant(x509.getNotAfter().toInstant(),ZoneId.systemDefault())));
System.out.println("\n");
}
});
JVM Parameters
Modify the java heap memory based on container memory using one of the following JVM parameters:
Parameter | Description |
---|---|
-XX:InitialRAMPercentage | The initial size of the heap based on the total container memory. |
-XX:MinRAMPercentage | The maximum heap size based on the size of the JVM running on small heap. The small is heap is of approximately 125MB. |
-XX:MaxRAMPercentage | The maximum heap size based on the size of the JVM running on greater than small heap. |
Displaying the Current Value
Use the following command the display the current value of the container aware JVM Parameters using the following:
docker container run -it --rm openjdk:17.0.2-slim java -XX:+PrintFlagsFinal -version | grep -E ".*RAMPercentage"
Expect to see something like the following:
double InitialRAMPercentage = 1.562500
{product} {default}
double MaxRAMPercentage = 25.000000
{product} {default}
double MinRAMPercentage = 50.000000
{product} {default}
Checking the Current Memory and CPU using JShell
-
Open a jshell in the container using the following:
docker container run -it --rm openjdk:17.0.2-slim jshell
-
Paste the following command in jshell:
var rt = Runtime.getRuntime(); System.out.printf("Heap size: %dMB%nMaximum size of heap: %dMB%nAvailable processors: %d%n", rt.totalMemory()/1024/1024, rt.maxMemory()/1024/1024, rt.availableProcessors());
-
Press enter.
Expect to see something similar to the following:
rt ==> java.lang.Runtime@1d81eb93 Heap size: 252MB Maximum size of heap: 3966MB Available processors: 16 $2 ==> java.io.PrintStream@34c45dca
-
Type the following in jshell and press enter.
/exit
Allocating a Memory and CPU to a Container
-
Execute the following command to allocate 100mb of memory and 1 CPU to the container:
docker container run -it --rm -m 100m --cpus=1 openjdk:17.0.2-slim jshell
-
Paste the following command in jshell:
var rt = Runtime.getRuntime(); System.out.printf("Heap size: %dMB%nMaximum size of heap: %dMB%nAvailable processors: %d%n", rt.totalMemory()/1024/1024, rt.maxMemory()/1024/1024, rt.availableProcessors());
-
Press enter.
Expect to see something similar to the following:
rt ==> java.lang.Runtime@6659c656 Heap size: 7MB Maximum size of heap: 48MB Available processors: 1 $2 ==> java.io.PrintStream@2d8e6db6
Notice the following:
Value Heap size 7MB Maximum size of heap 48MB Available processors 1 -
Type the following in jshell and press enter.
/exit
Modifying the Allocated Maximum Size of Heap Memory
-
Execute the following command to allocate 100mb of memory and 1 CPU to the container:
docker container run -it --rm -m 100m --cpus=1 openjdk:17.0.2-slim jshell -R-XX:MinRAMPercentage=80
-
Paste the following command in jshell:
var rt = Runtime.getRuntime(); System.out.printf("Heap size: %dMB%nMaximum size of heap: %dMB%nAvailable processors: %d%n", rt.totalMemory()/1024/1024, rt.maxMemory()/1024/1024, rt.availableProcessors());
-
Press enter.
Expect to see something similar to the following:
rt ==> java.lang.Runtime@6659c656 Heap size: 7MB Maximum size of heap: 77MB Available processors: 1 $2 ==> java.io.PrintStream@2d8e6db6
Notice the Maximum size of heap become 77MB. This is because of the JVM argument -XX:MinRAMPercentage=80 passed in jshell as:
-R-XX:MinRAMPercentage=80
We use the --XX:MinRAMPercentage=80 because the memory allocated is a small heap.
-
Type the following in jshell and press enter.
/exit
Listing the Available Random Algorithms
System.out.printf("%-13s| %s\n-------------|---------------------\n", "Group", "Name");
java.util.random.RandomGeneratorFactory.all()
.sorted(java.util.Comparator.comparing(java.util.random.RandomGeneratorFactory::name))
.forEach(factory -> System.out.printf("%-13s| %s\n", factory.group(), factory.name()));
The output is similar to the following:
Group | Name
-------------|---------------------
LXM | L128X1024MixRandom
LXM | L128X128MixRandom
LXM | L128X256MixRandom
LXM | L32X64MixRandom
LXM | L64X1024MixRandom
LXM | L64X128MixRandom
LXM | L64X128StarStarRandom
LXM | L64X256MixRandom
Legacy | Random
Legacy | SecureRandom
Legacy | SplittableRandom
Xoroshiro | Xoroshiro128PlusPlus
Xoshiro | Xoshiro256PlusPlus
Check from the following address on how to choose which algorithm to choose:
Creating an instance of RandomGenerator
The default algorithm (i.e. L32X64MixRandom)
var generator = java.util.random.RandomGenerator.getDefault();
The specific algorithm (e.g. L64X128MixRandom)
var generator = java.util.random.RandomGenerator.of("L64X128MixRandom");
Use the static method RandomGenerator.of and pass the name of the algorithm.
Generating Random Number
Use one of the following instance methods of the RandomGenerator class:
- nextDouble()
- nextDouble(double bound)
- nextDouble(double origin, double bound)
- nextFloat()
- nextFloat(float bound)
- nextFloat(float origin, float bound)
- nextInt()
- nextInt(int bound)
- nextInt(int origin, int bound)
- nextLong()
- nextLong(long bound)
- nextLong(long origin, long bound)
The origin parameter is inclusive and bound parameter is exclusive.
Example using a classic random algorithm
var generator = java.util.random.RandomGenerator.of("Random");
System.out.println(generator.nextInt());
The output is a random integer number.
Generating Random Number Using Streams
Use one of the following instance methods of RandomGenerators class to create streams:
- doubles()
- doubles(double origin, double bound)
- doubles(long streamSize)
- doubles(long streamSize, double origin, double bound)
- ints()
- ints(int origin, int bound)
- ints(long streamSize)
- ints(long streamSize, int origin, int bound)
- longs()
- longs(long origin, long bound)
- longs(long streamSize)
- longs(long streamSize, long origin, long bound)
The origin parameter is inclusive and bound parameter is exclusive.
Example using a classic random algorithm
var generator = java.util.random.RandomGenerator.of("Random");
var randomInt = generator.ints(100, 1, 100)
.filter(number -> number % 2 == 0 )
.findFirst();
randomInt.ifPresent(System.out::println);
The output is a random integer number.
Sealed classes and interfaces restrict which other classes or interfaces may extend or implement them.
public sealed interface IAnimal
permits AquaticAnimal, LandAnimal {
String lifespan();
}
Notice the use of the sealed modifier and permits keyword. The sealed modifier indicates that the class or interface is restricted. The permit keyword indicates which classes (or interfaces) can implement (or extends) it. Thus, the sealed modifier and the permit keyword must be used together.
public sealed abstract class AquaticAnimal implements IAnimal permits SeaTurtle {
}
The class (or interface) that can implement (or extend) a sealed interface (or class) must have one of the following modifiers:
- sealed
- non-sealed
- final
public non-sealed abstract class LandAnimal implements IAnimal {
}
Using the non-sealed modifier indicates that this class can be extended without restriction.
public sealed class Dog extends LandAnimal permits Boxer {
@Override
public String lifespan() {
return "10 - 13 years";
}
}
Limiting the hierarchy of Dog class to just Boxer class.
public final class Boxer extends Dog {
@Override
public String lifespan() {
return "10 - 12 years";
}
}
The final implementation of the Dog class.
public class Cat extends LandAnimal {
@Override
public String lifespan() {
return "12 - 18 years";
}
}
Since LandAnimal is non-sealed abstract class, it can be inherited without restriction.
public final class SeaTurtle extends AquaticAnimal {
@Override
public String lifespan() {
return "Up to 50 years or more";
}
}
SeaTurtle is the only class that can implement AquaticAnimal. Because this the only class permitted in the AquaticAnimal definition.
Recent Comments