Quick Note

For each part of this FRQ and the other three FRQs, I included two versions of the solution: one with no runtime (i.e. CollegeBoard’s key) and one with runtime.

Question 4: Interfaces (includes Classes and some Methods and Control Structures)

Directions: SHOW ALL YOUR WORK. REMEMBER THAT PROGRAM SEGMENTS ARE TO BE WRITTEN IN JAVA.

Notes:

Assume that the classes listed in the Java Quick Reference have been imported where appropriate.

Unless otherwise noted in the question, assume that parameters in method calls are not null and that methods are called only when their preconditions are satisfied.

In writing solutions for each question, you may use any of the accessible methods that are listed in classes defined in that question. Writing significant amounts of code that can be replaced by a call to one of these methods will not receive full credit.

This question involves the design of an interface, writing a class that implements the interface, and writing a method that uses the interface.

Question 4a

(a) A number group represents a group of integers defined in some way. It could be empty, or it could contain one or more integers.

Write an interface named NumberGroup that represents a group of integers. The interface should have a single contains method that determines if a given integer is in the group. For example, if group1 is of type NumberGroup, and it contains only the two numbers -5 and 3, then group1.contains(-5) would return true, and group1.contains(2) would return false.

Write the complete NumberGroup interface. It must have exactly one method.

No Runtime

public interface NumberGroup {
    boolean contains(int n);
}

With Runtime

public interface NumberGroup {
    boolean contains(int n);
}

// Test cases
class NumberGroupTest {
    public static void main(String[] args) {
        NumberGroup group = new NumberGroup() {
            @Override
            public boolean contains(int n) {
                // contains only -5 and 3
                return n == -5 || n == 3;
            }
        };

        // Test cases
        System.out.println("Test group contains -5: " + group.contains(-5)); // should return true
        System.out.println("Test group contains 2: " + group.contains(2)); // should return false
    }
}

NumberGroupTest.main(null);
Test group contains -5: true
Test group contains 2: false

Question 4b

(b) A range represents a number group that contains all (and only) the integers between a minimum value and a maximum value, inclusive. Write the Range class, which is a NumberGroup. The Range class represents the group of int values that range from a given minimum value up through a given maximum value, inclusive. For example,the declaration

NumberGroup range1 = new Range(-3, 2);

represents the group of integer values -3, -2, -1, 0, 1, 2.

Write the complete Range class. Include all necessary instance variables and methods as well as a constructor that takes two int parameters. The first parameter represents the minimum value, and the second parameter represents the maximum value of the range. You may assume that the minimum is less than or equal to the maximum.

No Runtime

public class Range implements NumberGroup {
    private int min, max;

    public Range(int min, int max){
        this.min = min;
        this.max = max;
    }

    public boolean contains(int value){
        return min <= value && value <= max;
    }
}

With Runtime

public interface NumberGroup {
    boolean contains(int value);
}

public class Range implements NumberGroup {
    private int min;
    private int max;

    public Range(int min, int max) {
        this.min = min;
        this.max = max;
    }

    public boolean contains(int value) {
        return value >= min && value <= max;
    }

    // returns a string representation of all values in the range
    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Range: ");
        for (int i = min; i <= max; i++) {
            builder.append(i).append(" ");
        }
        return builder.toString().trim(); 
    }
}

// Test cases
class RangeTest {
    public static void main(String[] args) {
        Range range = new Range(-3, 2);

        // Printing all values in the range
        System.out.println(range);

        // Test cases
        System.out.println("Range contains -3: " + range.contains(-3)); // should return true
        System.out.println("Range contains 0: " + range.contains(0)); // should return true
        System.out.println("Range contains 3: " + range.contains(3)); // should return false
    }
}

RangeTest.main(null);
Range: -3 -2 -1 0 1 2
Range contains -3: true
Range contains 0: true
Range contains 3: false

Question 4c

(c) The MultipleGroups class (not shown) represents a collection of NumberGroup objects and isa NumberGroup. The MultipleGroups class stores the number groups in the instance variable groupList (shown below), which is initialized in the constructor.

private List groupList;

Write the MultipleGroups method contains. The method takes an integer and returns true if and only if the integer is contained in one or more of the number groups in groupList.

For example, suppose multiple1 has been declared as an instance of MultipleGroups and consists of the three ranges created by the calls new Range(5, 8), new Range(10, 12), and new Range(1, 6). The following table shows the results of several calls to contains.

Complete method contains below.

No Runtime

public class MultipleGroups implements NumberGroup {
    public boolean contains(int num){
        for(NumberGroup ng : groupList){
            if(ng.contains(num)){
                return true;
            }
        }
        return false;
    }
}

With Runtime

import java.util.List;
import java.util.ArrayList;

public class MultipleGroups implements NumberGroup {
    private List<NumberGroup> groupList;

    public MultipleGroups() {
        groupList = new ArrayList<>();
        groupList.add(new Range(5, 8));
        groupList.add(new Range(10, 12));
        groupList.add(new Range(1, 6));
    }

    public boolean contains(int num) {
        for (NumberGroup group : groupList) {
            if (group.contains(num)) {
                return true;
            }
        }
        return false;
    }
}

// Test cases 
class MultipleGroupsTest {
    public static void main(String[] args) {
        MultipleGroups multiple = new MultipleGroups();

        // Test cases
        System.out.println("Multiple contains 3: " + multiple.contains(3)); // should return true
        System.out.println("Multiple contains 9: " + multiple.contains(9)); // should return false
        System.out.println("Multiple contains 5: " + multiple.contains(5)); // should return true
    }
}

MultipleGroupsTest.main(null);

Multiple contains 3: true
Multiple contains 9: false
Multiple contains 5: true

Reflection for FRQ 4

This question was about creating interfaces, which is technically no longer tested on the AP Exam. However, interfaces are still an important concept to know about as they can still have numerous applications, whether it is the projects we do in class or anything beyond that. One of the things that I noticed about this question and some of the other questions in general was that it was a little difficult for me to pinpoint what exact question type this was. Nowadays, it is easy to tell, but back in 2015, it appears that this question had a mixture of these topics, such as classes and methods and control structures. That really highlights how all those topics (methods and control structures, classes, arrays/arraylists, etc.) work together and in certain situations have to be used together. Although I have not had as much exposure to interfaces, I still found this FRQ a good source to practice on them, as that will ensure that I don’t completely disregard interfaces and their use even if they are not being tested on anymore.