Question 4: Methods and Control Structures

4a

PART 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.

import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        NumberGroup group1 = new IntegerList(Arrays.asList(100, 200));
        System.out.println(group1.contains(100)); // true
        System.out.println(group1.contains(300));  // false
    }

    // specific interface it is asking for part a
    public interface NumberGroup {
        boolean contains(int num);
    }

    public static class IntegerList implements NumberGroup {
        private List<Integer> numbers;

        public IntegerList(List<Integer> numbers) {
            this.numbers = numbers;
        }

        @Override
        public boolean contains(int num) {
            return numbers.contains(num);
        }
    }
}

Main.main(null);

Output:

true
false

4a Explanation

I started by defining an interface named NumberGroup as instructed, which represents a group of integers and contains a single method called contains. This method checks if a given integer is present within the group. Next, I implemented this interface in a class called IntegerList, which utilizes a List to store the numbers in the group. The constructor of IntegerList takes a List parameter, initializing the internal list with the provided numbers. Within the contains method of IntegerList, I utilized the List's built-in contains method to determine if the specified integer is present in the group. Finally, in the main method, I instantiated an IntegerList object named group1 with a list containing integers 100 and 200. Testing the contains method with various integers, I verified its functionality, where group1.contains(100) correctly returned true, and group1.contains(300) appropriately returned false, demonstrating the successful implementation of the NumberGroup interface.

4b

PART 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.

public class Main {
    public static void main(String[] args) {
        NumberGroup range1 = new Range(100, 200);
        System.out.println(range1.contains(150)); // true
        System.out.println(range1.contains(175));  // true
        System.out.println(range1.contains(300));  // false
    }

    // from part A
    public interface NumberGroup {
        boolean contains(int num);
    }

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

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

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

Main.main(null);

Output:

true
true
false

4b Explanation

I began by defining a class named Range that implements the NumberGroup interface, representing a number group consisting of integers within a specified range. The Range class includes two private instance variables, min and max, which denote the minimum and maximum values of the range, respectively. The constructor of the Range class takes two integer parameters, setting the values of min and max accordingly. Within the contains method of the Range class, I implemented the logic to determine whether a given integer falls within the specified range, utilizing a boolean expression that evaluates to true if the number is greater than or equal to min and less than or equal to max. Finally, in the main method, I instantiated a Range object named range1 with minimum and maximum values of 100 and 200, respectively. Testing the contains method with various integers, I verified its correctness, where range1.contains(150) and range1.contains(175) both correctly returned true, while range1.contains(300) appropriately returned false, demonstrating the successful implementation of the Range class as a NumberGroup.

4c

PART 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.

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

public class Main {
    public static void main(String[] args) {
        List<NumberGroup> groups = new ArrayList<>();
        groups.add(new Range(100, 200));
        groups.add(new Range(300, 400));
        groups.add(new Range(500, 600));

        MultipleGroups multiple1 = new MultipleGroups(groups);

        System.out.println(multiple1.contains(150)); // true
        System.out.println(multiple1.contains(250)); // false
        System.out.println(multiple1.contains(550)); // true
    }

    // from part A
    public interface NumberGroup {
        boolean contains(int num);
    }

    // from part B
    public static class Range implements NumberGroup {
        private int min;
        private int max;

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

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

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

        public MultipleGroups(List<NumberGroup> groupList) {
            this.groupList = groupList;
        }

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


        }
    }
}

Main.main(null);

Output:

true
false
true

4c Explanation

I focused on implementing the contains method within the MultipleGroups class. This class represents a collection of NumberGroup objects and implements the NumberGroup interface itself. The instance variable groupList holds the NumberGroup objects, initialized within the constructor. Within the contains method, I iterated through each NumberGroup object in the groupList using a for-each loop. For each group, I called its contains method to check if the provided integer is present within that group. If the contains method of any group returns true, indicating that the integer is found within at least one group, the contains method of MultipleGroups returns true immediately. Otherwise, if none of the groups contain the integer, the method returns false. To demonstrate the functionality of the implemented solution, I instantiated an instance of MultipleGroups named multiple1 with a list of NumberGroup objects, specifically Range objects representing different numerical ranges. Testing the contains method with various integers, I verified its accuracy in determining whether the integer is contained in one or more of the number groups in groupList. For example, calling multiple1.contains(150) correctly returned true, multiple1.contains(250) returned false as expected, and multiple1.contains(550) returned true, validating the successful implementation of the contains method within MultipleGroups.

package com.nighthawk.spring_portfolio.mvc.person;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;

/*
Extends the JpaRepository interface from Spring Data JPA.
-- Java Persistent API (JPA) - Hibernate: map, store, update and retrieve database
-- JpaRepository defines standard CRUD methods
-- Via JPA the developer can retrieve database from relational databases to Java objects and vice versa.
*/
public interface PersonJpaRepository extends JpaRepository<Person, Long> {
    Person findByEmail(String email);

    List<Person> findAllByOrderByNameAsc();

    // JPA query, findBy does JPA magic with "Name", "Containing", "Or", "Email", "IgnoreCase"
    List<Person> findByNameContainingIgnoreCaseOrEmailContainingIgnoreCase(String name, String email);

    /* Custom JPA query articles, there are articles that show custom SQL as well
       https://springframework.guru/spring-data-jpa-query/
       https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods
    */
    Person findByEmailAndPassword(String email, String password);

    // Custom JPA query
    @Query(
            value = "SELECT * FROM Person p WHERE p.name LIKE ?1 or p.email LIKE ?1",
            nativeQuery = true)
    List<Person> findByLikeTermNative(String term);
    /*
      https://www.baeldung.com/spring-data-jpa-query
    */
}

Relation to the FRQ

Through inheritance, the PersonJpaRepository extends JpaRepository, showcasing method sharing and coherence, reflecting concepts tested in FRQs. In my project, I’ve implemented a repository interface called PersonJpaRepository using Spring Data JPA to handle database operations for the Person entity. This interface extends JpaRepository and provides several methods for interacting with person data stored in a relational database. For instance, I’ve defined methods like findByEmail to retrieve a person by their email address and findAllByOrderByNameAsc to fetch all persons ordered by name in ascending order. Additionally, I’ve included custom query methods like findByLikeTermNative to execute native SQL queries for more complex operations. This is related to this FRQ because I created a Java interface named NumberGroup and a class Range that implements this interface. The Range class represents a range of numbers specified by a minimum and maximum value, and it includes a method contains to determine if a given number falls within that range. To fulfill the requirement of checking if a number is contained within any group in a list of NumberGroup objects, I implemented a standalone method contains that iterates through the list and returns true if the number is found within any NumberGroup, otherwise returning false. ```