Monday, February 13, 2023

Quiz yourself: Splitting Java streams and using escape characters

Oracle Java, Oracle Java Tutorial and Materials, Oracle Java Prep, Oracle Java Guides, Oracle Java Certification, Java Career, Java Jobs, Java Skill

Test your knowledge of the Pattern class and splitAsStream method


Given the following class

import java.util.Arrays;
import java.util.regex.Pattern;
public class FooBaz {
  static final Pattern PIPE_SPLITTER = Pattern.compile("\\|");
  public static void main(String[] args) {
    System.out.print(doIt("12|11|30"));
  }
  public int doIt(String s) {
    var a = PIPE_SPLITTER.splitAsStream(s)
       .mapToInt(v -> Integer.valueOf(v))
       .mapToObj(v -> new Integer[]{v % 3 == 0 ? 1 : 0, v % 5 == 0 ? 2 : 0, v})
       .reduce(new Integer[]{0, 0, 0}, (i, is) -> new Integer[]{i[0] + is[0], i[1] + is[1], i[2] + is[2]});
    return Arrays.stream(a).mapToInt(Integer::intValue).sum();
  }
}

What is the result? Choose one.

A. 56 is the output.
B. 57 is the output.
C. 58 is the output.
D. 59 is the output.
E. Compilation fails.

Answer. When you see an exam question that has unreasonably complex code, be sure to check for simple things first. You won’t always find the answer there, but if checking the hard stuff is going to take a long time, it’s smart to check the easy stuff first. In this example, the code does not, in fact, compile. The reason is simple: The static main method attempts to call the doIt method without any explicit prefix, and such an invocation can work only for a static doIt() method. However, doIt() is an instance method and in the absence of an explicit prefix, such an invocation will fail. From this you can quickly determine that option E is correct, mark that as your answer, and move on to the next question.

Now that you know the correct answer, let’s make this discussion more interesting by pretending that the doIt() method was static or that an explicit instance prefix was provided for the invocation of the doIt() method.

First, notice that the splitAsStream method splits the string argument "12|11|30" into three text chunks—"12", "11", and "30"—which are then converted to a stream of equivalent primitive int values by the mapToInt operation.

As side notes, observe three things: the use of the Pattern class’s splitAsStream method, the precompilation of the pattern, and the escaping of the vertical bar character in the regular expression pattern.

◉ The splitAsStream method is more direct than the more common approach of extracting items from the source text to an intermediate array using the simple split method and then making a stream from the elements of the array as a second step.

◉ The precompilation of the regular expression pattern makes no difference here, but notice that the pattern is declared as a static final, rather than being embedded in the body of the method. Turning a textual regular expression into the representation that actually performs pattern matching is a fairly CPU-intensive task, so it’s generally a good idea to arrange that a pattern is precompiled in this way just once, rather than referring to it in the string literal form in a way that might involve it being compiled each time a loop executes that code.

◉ Note the nature of the regular expression literal. The simple vertical bar (or pipe) character represents an OR operation and must be escaped. However, a single backslash would be an attempt to escape the vertical bar in the parsing of the string literal, which is probably not what you want. You need to make a literal containing the character sequence “backslash, vertical bar.” Because backslash is itself the escape character, it must be escaped, so two backslashes in the source code make one in the binary code, which is what’s desired.

Going back to the operation of this stream, the three int values are mapped to a stream of Integer arrays, containing the following data:

[1, 0, 12]
[0, 0, 11]
[1, 2, 30]

Notice that the conditional operators in the mapToObj argument will put 0 in the first array element if the int in the stream is exactly divisible by 3 but put 1 in otherwise. The second element of the array will be 0 if the int is exactly divisible by 5 but will be 2 otherwise. The third element is simply the int value from the stream.

Next the stream is reduced to a single Integer[] by summing values with the same indices to produce the following result in the variable a:

[2, 2, 53]

In the final step, the array noted above is converted to a stream of Integer objects, which are then converted to primitives and then reduced to the sum of all elements, producing 57 as the output. Thus, if the code had actually compiled, option B would have been correct.

Conclusion. The correct answer is option E.

Source: oracle.com

Related Posts

0 comments:

Post a Comment