laitimes

Java features that are useful but not well known

Author | Piotr Mińkowski

Translated by | Zhang Weibin

Planning | Yan Garden

This article was originally published on Piotr Mińkowski's personal site Medium website, with the author's permission and shared by InfoQ Chinese Translator.

In this article, you'll learn about some useful Java features that you may not have heard of before. This is a list of private features that I discovered and collated recently when I read an article about Java. I'm not going to focus on languages, I'm going to focus on APIs.

Do you like Java and want to learn about its latest features? If yes, you can read my article on what's new after Java 8. Next, in this article, you'll learn about eight features that are not well known but are very useful. So let's get started!

Delay queues

To use this collection, first, our class needs to implement the getDelay method of the Delayed interface. Of course, it doesn't have to be a class, it can also be a Java Record.

Suppose we want to delay an element by 10 seconds, then we just need to set the time to the current time plus 10 seconds on the DelayedEvent class.

What output can we see for the above code? This is shown below.

The time format supports displaying the time period of the day

Well, I'll admit that this Java feature isn't of much use to most of you, but I have a soft spot for it... Java 8 has made many improvements to the time-handling API. Starting with this version of Java, in most cases we don't need any additional libraries to handle time, like Joda Time. As you might not imagine, starting with Java 16, we could even use standard formatters to express the time of day, which is "in the morning" or "in the afternoon." This is a new format pattern called B.

The following is the result of my run. Of course, your results may vary depending on the time.

Well, wait a minute... Now, you might ask why this format is called B. In fact, it is not the most intuitive name for this type of format. But perhaps the table below will solve all our doubts. It is a fragment of pattern characters and symbols that DateTimeFormatter is able to handle. I suspect that B is the first letter to come out of the free. Of course, I could be wrong.

Java features that are useful but not well known

StampedLock

In my opinion, Java Concurrent is one of the most interesting Java packages. It is also a package that is not well known to developers, especially when developers primarily use web frameworks. How many of us have used locks in Java? Locks are a more flexible thread synchronization mechanism than synchronized blocks. Starting with Java 8, we can use a new type of lock called StampedLock. StampedLock is an alternative to ReadWriteLock. It allows optimistic locking of read operations. What's more, it performs better than ReentrantReadWriteLock.

Suppose we have two threads. The first thread updates a balance, while the second thread reads the current value of the balance. In order to update the balance, we of course need to read its current value first. Here, we need some sort of synchronization mechanism, assuming that the first thread runs multiple times at the same time. The second thread illustrates how to use optimistic locks for read operations.

Now, we run both threads 50 times at the same time. Its results should be as expected, with a final balance of 60,000.

Concurrent accumulator

In a Java Concurrent package, it's not just locks that's interesting, it's also interesting that another interesting thing is the concurrent accumulator. We also have concurrent adders, but they function very similarly. LongAccumulator (we also have DoubleAccumulator) updates a value with a function provided to it. In many scenarios, it allows us to implement lock-free algorithms. When multiple threads update a common value, it is usually more appropriate than AtomicLong.

Let's see how it works. To create it, we need to set two parameters in the constructor. The first argument is a function that calculates the result of accumulation. Typically, we use the sum method. The second parameter represents the initial value of the accumulator.

Now, let's create a LongAccumulator with an initial value of 10000 and call the accumulate() method from multiple threads. The end result? If you think about it, we did exactly the same thing as the previous section, but this time there were no locks.

Hexadecimal format

There is no big story about this feature. Sometimes we need to convert between hexadecimal strings, bytes, or characters. Starting with Java 17, we can do this using the HexFormat class. Just create an instance of HexFormat, and then you can format the input byte array, for example, as a hexadecimal string. You can also parse the input hexadecimal string as a byte array, as shown below.

Binary lookup of arrays

Suppose we want to insert a new element in a sorted array. Arrays.binarySearch() returns the index of the search key if the array already contains the element, otherwise, it returns an insertion point, which we can use to calculate the index of the new key: -(insertion point)-1. In addition, in Java, the binarySearch method is the easiest and most efficient way to find elements in an ordered array.

Let's consider the following example. We have an array of inputs with four elements, arranged in ascending order. We want to insert the number 3 in this array, and the following code shows how to calculate the index of the insertion point.

Bit Set

What if we need to do something with the bit array? Would you use boolean[] to do this? In fact, there is a more efficient and memory-saving way to achieve this. This is the BitSet class. The BitSet class allows us to store and manipulate arrays of bits. It consumes 8 times less memory than boolean[]. We can perform logical operations on arrays, such as: and, or, xor.

Let's say we have an array of two bits, and we want to perform xor operations on them. In order to do this, we need to create two instances of bitSets and insert sample elements in the instance as shown below. Finally, call the xor method on one of the BitSet instances and take the second BitSet instance as an argument.

The following is the result of running the preceding code:

Phaser

Finally, we introduce the last interesting Java feature of this article. Like some other examples, it is an element of the Java Concurrent package, known as Phaser. It is quite similar to the more well-known CountDownLatch. However, it offers some extra features. It allows us to set the dynamic number of threads that we need to wait for before proceeding with execution. In Phaser, a defined number of threads need to wait on the barrier before proceeding to the next execution. Thanks to this, we can coordinate the execution of multiple stages.

In the example below, we set up a barrier with 50 threads that needs to be reached before proceeding to the next execution phase. We then create a thread that calls the arriveAndAwaitAdvance() method on the Phaser instance. It blocks threads until all 50 threads reach the barrier. It then enters phase-1 and again calls the arriveAndAwaitAdvance() method.

The following is the result of executing the preceding code:

Java features that are useful but not well known

https://piotrminkowski.com/2022/01/05/useful-unknown-java-features/

Read on