Programmer II Chapter 4: Functional Programming Flashcards
What functional interface would you use in these three situations?
Returns a String without taking any parameters
Returns a Boolean and takes a String
Returns an Integer and takes two Integers
Supplier < String >
Function < String, Boolean >
BiFunction < Integer, Integer, Integer > or BinaryOperator < Integer >
The first one is a Supplier < String > because it generates an object and takes zero parameters. The second one is a Function < String,Boolean > because it takes one parameter and returns another type. It’s a little tricky.You might think it is a Predicate < String >. Note that a Predicate returns a boolean primitive and not a Boolean object. Finally, the third one is either a BinaryOperator < Integer > or aBiFunction < Integer,Integer,Integer > . Since BinaryOperator is a special case of BiFunction, either is a correct answer. BinaryOperator < Integer > is the better answer of the two since it is more specific.
What functional interface would you use to fill in the blank for these?
6: ____________ < List > ex1 = x -> ““.equals(x.get(0));
7: ____________ < Long > ex2 = (Long l) -> System.out.println(l);
8: ____________ < String, String > ex3 = (s1, s2) -> false;
Predicate
Consumer
BiPredicate
Line 6 passes one List parameter to the lambda and returns a boolean. This tells us that it is a Predicate or Function. Since the generic declaration has only one parameter, it is a Predicate.
Line 7 passes one Long parameter to the lambda and doesn’t return anything. This tells us that it is a Consumer.
Line 8 takes two parameters and returns a boolean. When you see a boolean returned, think Predicate unless the generics specify a Boolean return type. In this case, there are two parameters, so it is a BiPredicate.
Why do these lines not compile?
6: Function < List < String > > ex1 = x -> x.get(0); // DOES NOT COMPILE
7: UnaryOperator < Long > ex2 = (Long l) -> 3.14; // DOES NOT COMIPLE
8: Predicate ex4 = String::isEmpty; // DOES NOT COMPILE
Line 6 claims to be a Function. A Function needs to specify two generics—the input parameter type and the return value type. The return value type is missing from line 6, causing the code not to compile. Line 7 is a UnaryOperator, which returns the same type as it is passed in. The example returns a double rather than a Long, causing the code not to compile.
Line 8 is missing the generic for Predicate. This makes the parameter that was passed an Object rather than a String. The lambda expects a String because it calls a method that exists on String rather than Object. Therefore, it doesn’t compile.
What does this do?
Stream.generate(() -> "Elsa") .filter(n -> n.length() == 4) .sorted() .limit(2) .forEach(System.out::println);
It hangs until you kill the program or it throws an exception after running out of memory. sorted() waits until everything to sort is present. That never happens because there is an infinite stream.
What does this do?
Stream.generate(() -> "Elsa") .filter(n -> n.length() == 4) .limit(2) .sorted() .forEach(System.out::println);
It prints Elsa twice
What does this print?
var infinite = Stream.iterate(1, x -> x + 1); infinite.limit(5) .peek(System.out::print) .filter(x -> x % 2 == 1) .forEach(System.out::print);
11233455
As the first element passes through, 1 shows up in the peek() and print(). The second element makes it past limit() and peek(), but it gets caught in filter(). The third and fifth elements behave like the first element. The fourth behaves like the second.
Which functional interface would you use to fill in the blank to make the following code compile?
var d = 1.0; \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_ f1 = x -> 1; f1.applyAsInt(d);
IntFunction, DoubleToIntFunction
You can see that the functional interface in question takes a double parameter and returns an int. You can also see that it has a single abstract method named applyAsInt. The DoubleToIntFunction and ToIntFunction meet all three of those criteria.
What does this print?
25: var cats = new ArrayList < String > ();
26: cats.add(“Annie”);
27: cats.add(“Ripley”);
28: var stream = cats.stream();
29: cats.add(“KC”);
30: System.out.println(stream.count());
3
Lines 25–27 create a List with two elements. Line 28 requests that a stream becreated from that List. Remember that streams are lazily evaluated. This means that the stream isn’tactually created on line 28. An object is created that knows where to look for the data when it is needed.On line 29, the List gets a new element. On line 30, the stream pipeline actually runs. The stream pipelineruns first, looking at the source and seeing three elements.
What could be the output of the following?
var stream = Stream.iterate("", (s) -> s + "1"); System.out.println(stream.limit(2).map(x -> x + "2"));
A. 12112 B. 212 C. 212112 D. java.util.stream.ReferencePipeline$3@4517d9a3 E. The code does not compile. F. An exception is thrown. G. The code hangs.
D.
No terminal operation is called, so the stream never executes. The first line creates an infinitestream reference. If the stream were executed on the second line, it would get the first two elementsfrom that infinite stream, “” and “1”, and add an extra character, resulting in “2” and “12”,respectively. Since the stream is not executed, the reference is printed instead.
What could be the output of the following?
Predicate < String > predicate = s -> s.startsWith("g"); var stream1 = Stream.generate(() -> "growl!"); var stream2 = Stream.generate(() -> "growl!"); var b1 = stream1.anyMatch(predicate); var b2 = stream2.allMatch(predicate); System.out.println(b1 + " " + b2);
A. true false B. true true C. java.util.stream.ReferencePipeline$3@4517d9a3 D. The code does not compile. E. An exception is thrown. F. The code hangs
F.
Both streams created in this code snippet are infinite streams. The variable b1 is set to true since anyMatch() terminates. Even though the stream is infinite, Java finds a match on the first element and stops looking. However, when allMatch() runs, it needs to keep going until the end of the stream since it keeps finding matches. Since all elements continue to match, the program hangs.
What could be the output of the following?
Predicate < String > predicate = s -> s.length() > 3; var stream = Stream.iterate("-", s -> ! s.isEmpty(), (s) -> s + s); var b1 = stream.noneMatch(predicate); var b2 = stream.anyMatch(predicate); System.out.println(b1 + " " + b2);
A. false false B. false true C. java.util.stream.ReferencePipeline$3@4517d9a3 D. The code does not compile. E. An exception is thrown. F. The code hangs
E. An infinite stream is generated where each element is twice as long as the previous one. While thiscode uses the three-parameter iterate() method, the condition is never false. The variable b1 is setto false because Java finds an element that matches when it gets to the element of length 4. However,the next line tries to operate on the same stream. Since streams can be used only once, this throws anexception that the “stream has already been operated upon or closed.” If two different streams wereused, the result would be option B.
Which are true statements about terminal operations in a stream that runs successfully? (Choose all that apply.)
A. At most, one terminal operation can exist in a stream pipeline.
B. Terminal operations are a required part of the stream pipeline in order to get a result.
C. Terminal operations have Stream as the return type.
D. The peek() method is an example of a terminal operation.
E. The referenced Stream may be used after calling a terminal operation
A, B.
Terminal operations are the final step in a stream pipeline. Exactly one is required, because ittriggers the execution of the entire stream pipeline. Therefore, options A and B are correct. Option Cis true of intermediate operations, rather than terminal operations. Option D is incorrect becausepeek() is an intermediate operation. Finally, option E is incorrect because once a stream pipeline isrun, the Stream is marked invalid.
Which of the following sets result to 8.0? (Choose all that apply.)
A.
double result = LongStream.of(6L, 8L, 10L)
.mapToInt(x -> (int) x)
.collect(Collectors.groupingBy(x -> x))
.keySet()
.stream()
.collect(Collectors.averagingInt(x -> x));
B.
double result = LongStream.of(6L, 8L, 10L)
.mapToInt(x -> x)
.boxed()
.collect(Collectors.groupingBy(x -> x))
.keySet()
.stream()
.collect(Collectors.averagingInt(x -> x));
C.
double result = LongStream.of(6L, 8L, 10L)
.mapToInt(x -> (int) x)
.boxed()
.collect(Collectors.groupingBy(x -> x))
.keySet()
.stream()
.collect(Collectors.averagingInt(x -> x));
D.
double result = LongStream.of(6L, 8L, 10L)
.mapToInt(x -> (int) x)
.collect(Collectors.groupingBy(x -> x, Collectors.toSet()))
.keySet()
.stream()
.collect(Collectors.averagingInt(x -> x));
E.
double result = LongStream.of(6L, 8L, 10L) .mapToInt(x -> x)
.boxed()
.collect(Collectors.groupingBy(x -> x, Collectors.toSet()))
.keySet()
.stream()
.collect(Collectors.averagingInt(x -> x));F. double result = LongStream.of(6L, 8L, 10L)
.mapToInt(x -> (int) x)
.boxed()
.collect(Collectors.groupingBy(x -> x, Collectors.toSet()))
.keySet()
.stream()
.collect(Collectors.averagingInt(x -> x));
C, F.
Yes, we know this question is a lot of reading. Remember to look for the differences betweenoptions rather than studying each line. These options all have much in common. All of them start outwith a LongStream and attempt to convert it to an IntStream. However, options B and E are incorrectbecause they do not cast the long to an int, resulting in a compiler error on the mapToInt() calls.
Next, we hit the second difference. Options A and D are incorrect because they are missing boxed()before the collect() call. Since groupingBy() is creating a Collection, we need a nonprimitiveStream. The final difference is that option F specifies the type of Collection. This is allowed,though, meaning both options C and F are correct.
Which of the following can fill in the blank so that the code prints out false? (Choose all that apply.)
var s = Stream.generate(() -> "meow"); var match = s.\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_(String::isEmpty); System.out.println(match);
A. allMatch B. anyMatch C. findAny D. findFirst E. noneMatch F. None of the above
A. Options C and D do not compile because these methods do not take a Predicate parameter and do not return a boolean. When working with streams, it is important to remember the behavior of the underlying functional interfaces. Options B and E are incorrect. While the code compiles, it runs infinitely. The stream has no way to know that a match won’t show up later. Option A is correct because it is safe to return false as soon as one element passes through the stream that doesn’t match.
We have a method that returns a sorted list without changing the original. Which of the following can replace the method implementation to do the same with streams?
private static List < String > sort(List < String > list) { var copy = new ArrayList < String > (list); Collections.sort(copy, (a, b) -> b.compareTo(a)); return copy; }
A.
return list.stream()
.compare((a, b) -> b.compareTo(a))
.collect(Collectors.toList());
B.
return list.stream()
.compare((a, b) -> b.compareTo(a))
.sort();
C.
return list.stream()
.compareTo((a, b) -> b.compareTo(a))
.collect(Collectors.toList());
D.
return list.stream()
.compareTo((a, b) -> b.compareTo(a))
.sort();
E.
return list.stream()
.sorted((a, b) -> b.compareTo(a))
.collect();
F.
return list.stream()
.sorted((a, b) -> b.compareTo(a))
.collect(Collectors.toList());
F. There is no Stream < T > method called compare() or compareTo(), so options A through D can beeliminated. The sorted() method is correct to use in a stream pipeline to return a sorted Stream. Thecollect() method can be used to turn the stream into a List. The collect() method requires acollector be selected, making option E incorrect and option F correct.