Visit the secret-handshake exercise on Exercism to read the full instructions and download the exercise files.
Dig Deeper
for loop
for loop
import java.util.List;
import java.util.Vector;
class HandshakeCalculator {
List < Signal > calculateHandshake(int number) {
final List < Signal > output = new Vector < Signal > ();
int action = 0, action_incr = 1, end = Signal.values().length;
if ((number & 16) != 0) {
action = 3;
action_incr = -1;
end = -1;
}
for (; action != end; action += action_incr)
if ((number & (1 << action)) != 0)
output.add(Signal.values()[action]);
return output;
}
}
This approach starts by importing from packages for what will be needed.
In the calculateHandshake() method, a final List is defined to hold the signals.
It is final because it does not need to be reassigned after it is created.
A series of variables are defined and initialized for normal looping through the Signal values collection.
Normal looping would start at index 0 and proceed by adding 1 to the index up to but not including
the length of the Signal values collection.
The number is then compared with 16 by using the bitwise AND operator.
For example, given the bitwise value is 16 (binary 10000) and the input is 24 (binary 11000),
then ANDing 10000 with 11000 results in 10000, which is not 0, so the number contains bitwise16.
Given the bitwise value is 16 (binary 10000) and the input is 8 (binary 01000),
then ANDing 10000 with 01000 results in 00000, which is 0, so the number does not contain bitwise16.
If the number contains bitwise 16, then the looping variables are set to iterate in reverse.
The for loop is set up with the looping variables.
In the body of the for loop, the left shift operator is used
to shift 1 to the left for the number of places of the value of the action variable.
(The action variable is for the index in the Signals values collection.)
The bitwise AND operator is used to compare the bitwise value of the Signals index with the number.
For example, if the index is 2 (binary 010) and the input is 6 (binary 110),
then ANDing 010 with 110 results in 010, which is not 0, so the input contains bitwise2.
If the index value is 2 (binary 010) and the input is 4 (binary 100),
then ANDing 010 with 100 results in 000, which is 0, so the input does not contain bitwise 2.
If the number contains the bitwise value of the index, then the Signal value at that index is added to the List.
After the for loop is done, the List is returned from calculateHandshake().
IntStream
IntStream
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](https://www.geeksforgeeks.org/java-lambda-expression-variable-capturing-with-examples/) the variable.
To capture a variable, it must be in the enclosing [scope](https://www.geeksforgeeks.org/variable-scope-in-java/)
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 ANDing 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 ANDing 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().
Source: Exercism java/secret-handshake