Solution for Programming Exercise 4.5
This page contains a sample solution to one of the exercises from Introduction to Programming Using Java.
Exercise 4.5:
This exercise asks you to write a few lambda expressions and a function that returns a lambda expression as its value. Suppose that a function interface ArrayProcessor is defined as
public interface ArrayProcessor { double apply( double[] array ); }
Write a class that defines four public static final variables of type ArrayProcessor that process an array in the following ways: find the maximum value in the array, find the minimum value in an array, find the sum of the values in the array, and find the average of the values in the array. In each case, the value of the variable should be given by a lambda expression. The class should also define a function
public static ArrayProcessor counter( double value ) { ...
This function should return an ArrayProcessor that counts the number of times that value occurs in an array. The return value should be given as a lambda expression.
The class should have a main() routine that tests your work. The program that you write for this exercise will need access to the file ArrayProcessor.java, which defines the functional interface.
The interface ArrayProcessor defines a function apply(array) that takes an array of type double[] and that returns a double. A lambda expression of type ArrayList will typically take the form
array -> { statements-to-compute-value return a-double-value; }
(Of course, the name of the parameter, array, could be anything.) For example, a lambda expression for finding the sum of the numbers in the array could be written
array -> { double total = 0; for (int i = 0; i < array.length; i++) { total = total + array[i]; } return total; }
This lambda expression is a value of type ArrayProcessor. For this exercise, we are supposed to assign this lambda expression to a public static final member variable of type ArrayProcessor. Calling that variable sumer, this takes the form:
public static final ArrayProcessor sumer = array -> { double total = 0; for (int i = 0; i < array.length; i++) { total += array[i]; } return total; };
Note the semicolon at the end. The semicolon is not part of the lambda expression; it marks the end of the assignment statement.
Lambda expressions for the minimum and maximum of an array can be handled in a similar way. So could the average, but the average of an array is just the sum of the array divided by its length. Since we already have the ArrayProcessor sumer for computing the sum of an array, we might as well use it for computing the average. To apply sumer to an array, A, of type double[], we have to call the apply() function that is defined by the ArrayProcessor interface: sumer.apply(A). So, we can define an ArrayProcessor for computing the average of an array by:
public static final ArrayProcessor averager = array -> sumer.apply(array) / array.length;
When counting the number of times that a value appears in array, the answer depends on which value is being counted. That is, an ArrayProcessor that counts the number of times a value appears in an array is a function of the value that is being counted. The counter function that we are asked to write can simply return an appropriate lambda expression:
public static ArrayProcessor counter( double value ) { return array -> { int count = 0; for (int i = 0; i < array.length; i++) { if ( array[i] == value ) count++; } return count; }; }
Note that the parameter, value, is used in the definition of the array. So, for example, counter(17.0) will return an ArrayProcessor whose apply() method will count the number of times 17.0 occurs in an array. In my solution, I use that apply method in an expression of the form counter(17.0).apply(secondList), where secondList is a variable of type double[]. Take a look at the main() routine in the program below to see how the other ArrayProcessors are used.
/** * This class defines several public static member variables of * type ArrayProcessor that process arrays in various ways. It * also defines a function that can create ArrayProcessors for * counting occurrences of values in an array. (Note that this * program depends on interface ArrayProcessor.) */ public class LambdaTest { /** * This function returns an ArrayProcessor that counts * the number of times a certain value occurs in an array * of doubles. The parameter specifies the value that is * to be counted. */ public static ArrayProcessor counter( double value ) { return array -> { int count = 0; for (int i = 0; i < array.length; i++) { if ( array[i] == value ) count++; } return count; }; } /** * An ArrayProcessor that computes and returns the maximum * value of an array. (The array must have length at least 1.) */ public static final ArrayProcessor maxer = array -> { double max = array[0]; for (int i = 0; i < array.length; i++) { if ( array[i] > max) max = array[i]; } return max; }; /** * An ArrayProcessor that computes and returns the minimum * value of an array. (The array must have length at least 1.) */ public static final ArrayProcessor miner = array -> { double min = array[0]; for (int i = 0; i < array.length; i++) { if ( array[i] < min) min = array[i]; } return min; }; /** * An ArrayProcessor that computes and returns the sum of the * values in an array. (The array must have length at least 1.) */ public static final ArrayProcessor sumer = array -> { double total = 0; for (int i = 0; i < array.length; i++) { total += array[i]; } return total; }; /** * An ArrayProcessor that computes and returns the average of the * values in an array. (The array must have length at least 1.) */ public static final ArrayProcessor averager = array -> sumer.apply(array) / array.length; //--------------------------------------------------------------------------------------------------- /** * A main() routine to test the (other) public members of this class. */ public static void main(String[] args) { double[] firstList = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; double[] secondList = { 17.0, 3.14, 17.0, -3.4, 17.0, 42.0, 29.2, 3.14 }; System.out.println("Sum of first list (should be 55): " + sumer.apply(firstList) ); System.out.println("Average of first list (should be 5.5): " + averager.apply(firstList) ); System.out.println("Minimum of second list (should be -3.4): " + miner.apply(secondList) ); System.out.println("Maximum of second list (should be 42.0): " + maxer.apply(secondList) ); System.out.println(); System.out.println("Count of 17.0 in second list (should be 3): " + counter(17.0).apply(secondList) ); System.out.println("Count of 20.0 in second list (should be 0): " + counter(20.0).apply(secondList) ); System.out.println("Count of 5.0 in first list (should be 1): " + counter(5.0).apply(firstList) ); } } // end class LambdaTest