import java.util.Collections;
import java.util.List;
import java.util.function.IntPredicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
final class HandshakeCalculator {
public List < Signal > calculateHandshake(int n) {
IntPredicate isBitOn = bitIndex -> ((1 << bitIndex) & n) > 0;
List < Signal > signals = IntStream.range(0, Signal.values().length)
.filter(isBitOn)
.mapToObj(i -> Signal.values()[i])
.collect(Collectors.toList());
if (isBitOn.test(Signal.values().length)) {
Collections.reverse(signals);
}
return signals;
}
}
This approach starts by importing from packages for what will be needed.
In the calculateHandshake()
method, an IntPredicate
is defined which takes an int
argument and returns a bool
value.
The int
argument is passed to a lambda which shifts 1
to the left for the number of places of the value of the int
index.
It does this by use of the left shift operator.
So, if the bit index is 2
, then 1
would be shifted left two places for a binary value of 0100
, which is decimal 4
.
It then compares the bitwise value with the int
argument to the calculateHandshake()
method by using the bitwise AND operator.
Although the argument to calculateHandshake()
is not directly passed to the lambda, the lambda can use it.
To do so is called capturing the variable.
To capture a variable, it must be in the enclosing scope
of the lambda, and it must be effectively final
,
meaning that is is not changed in the course of the program.
If comparing the bitwise value with the input results in a non-zero bitwise value, then the input contains the value of the bitwise value.
For example, if the bitwise value is 2
(binary 010
) and the input is 6
(binary 110
),
then AND
ing 010
with 110
results in 010
, which is not 0
, so the input contains bitwise2
.
If the bitwise value is 2
(binary 010
) and the input is 4
(binary 100
),
then AND
ing 010
with 100
results in 000
, which is 0
, so the input does not contain bitwise 2
.
An IntStream
is defined which uses its range()
method to iterate from 0
up to but not including
the length of the values collection in the Signals
enum.
The numbers correspond with the indexes of the Signal
values.
Each index is passed to the filter()
method, where it is passed to the IntPredicate
for filtering in
only those indexes that are contained in the input number.
The surviving index numbers are passed into the mapToObj()
method which takes the index in its lambda
and returns the Signal
value at that index.
The collect()
method assembles the matching Signal
values into a List
.
The IntPredicate
is used once more to compare the input number with the bitwise value 16
(binary 10000
).
The bit index of 4
to pass in happens to be the length of the Signal
values collection.
If the input contains bitwise 16
, then the List
is reversed.
Finally, the List
is returned from calculateHandshake()
.