Backend

<Backend> Java / Generic 예제문제 2

이게왜 2023. 11. 8. 13:17

https://rezerocodinglife.tistory.com/22

 

Start <명품JAVA> ArrayList

명품자바의 예제문제, 실습문제를 풀며 공부해 나갑니다. 목표는 Collection, Generic, Comparable, Comparator, Iterable, Iterator, Stream, Lambda Expression등을 공부하여 이를 활용한 몬테카를로 시뮬레이션 미니 프

rezerocodinglife.tistory.com

공부를 시작하며 작성한 글 입니다. 공부하며 사용한 자료들이 있으니 참고하시면 좋겠습니다.

 

이번 글에서는 또다른 Generic 예제를 풀어보았습니다.

 

<문제 출처 : https://math.hws.edu/javanotes/c10/exercises.html>

 

Exercise 10.4:

A predicate is a boolean-valued function with one parameter. Java has the parameterized functional interface Predicate<T>, from package java.util.function, to represent predicates. The definition of Predicate<T> could be:

public interface Predicate<T> {
    public boolean test( T obj );
}

The idea is that an object that implements this interface knows how to "test" objects of type T in some way. Java already has some methods that use predicates, such as the removeIf(p) method that is defined for any Collection. (See Subsection 10.6.1). However, this exercise asks you to write a few similar methods yourself. Define a class that contains the following generic static methods for working with predicate objects. The name of the class should be Predicates, in analogy with the standard class Collections that provides various static methods for working with collections. You should not use the stream API for this exercise.

public static <T> void remove(Collection<T> coll, Predicate<T> pred)
   // Remove every object, obj, from coll for which pred.test(obj) 
   // is true.  (This does the same thing as coll.removeIf(pred).)
   
public static <T> void retain(Collection<T> coll, Predicate<T> pred)
   // Remove every object, obj, from coll for which
   // pred.test(obj) is false.  (That is, retain the
   // objects for which the predicate is true.)
   
public static <T> List<T> collect(Collection<T> coll, Predicate<T> pred)
   // Return a List that contains all the objects, obj,
   // from the collection, coll, such that pred.test(obj)
   // is true.
   
public static <T> int find(ArrayList<T> list, Predicate<T> pred)
   // Return the index of the first item in list
   // for which the predicate is true, if any.
   // If there is no such item, return -1.
Generic을 이용하여 Predicates Calss의 Method를 정의하는 문제입니다.
또한 이를 테스트하는 코드도 작성해야 합니다.

 

<풀이한 Predicates Class>

package Chapter10;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.function.Predicate;

public class Predicates {

    public static <T> void remove(Collection<T> coll, Predicate<T> pred) {
        Iterator<T> iterator = coll.iterator();
        while (iterator.hasNext()) {
//            T item = iterator.next();
//            if(pred.test(item)){
//                iterator.remove();
//            }
            if (pred.test(iterator.next())) {
                iterator.remove();
            }
        }
    }

    public static <T> void retain(Collection<T> coll, Predicate<T> pred) {
        Iterator<T> iterator = coll.iterator();
        while (iterator.hasNext()) {
            if (!pred.test(iterator.next())) {
                iterator.remove();
            }
        }
    }

    public static <T> List<T> collect(Collection<T> coll, Predicate<T> pred) {
        List<T> list = new ArrayList<>();
        for (T item : coll) {
            if (pred.test(item)) {
                list.add(item);
            }
        }
        return list;
    }

    public static <T> int find(ArrayList<T> list, Predicate<T> pred) {
        for (int i = 0; i < list.size(); i++) {
            T item = list.get(i);
            if (pred.test(item)) {
                return i;
            }
        }
        return -1;
    }
}

 


코드를 작성하기에 앞서 Java의 Predicate Interface를 살펴보아야 했습니다.

 Predicate의 test() MethodGeneric Type의 parameter를 전달받아 특정 작업을 거친 후 boolean type의 값을 반환합니다.
여기서 '특정 작업' 은 사용자가 정의 가능합니다.

 

<TestPredicates Class>

package Chapter10;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.TreeSet;
import java.util.function.Predicate;

public class TestPredicates {

    public static Collection<Integer> makeSet() {
        Collection<Integer> set = new TreeSet<>();
        set.add(Integer.valueOf(32));
        set.add(Integer.valueOf(17));
        set.add(Integer.valueOf(142));
        set.add(Integer.valueOf(56));
        set.add(Integer.valueOf(1899));
        set.add(Integer.valueOf(57));
        set.add(Integer.valueOf(999));
        set.add(Integer.valueOf(86));
        set.add(Integer.valueOf(83));
        set.add(Integer.valueOf(100));
        return set;
    }

    public static void main(String[] args) {

        Collection<Integer> coll;

        List<Integer> result;

        Predicate<Integer> pred = i -> (i % 2 == 0);

        coll = makeSet();
        System.out.println("Original collection: " + coll);


        Predicates.remove(coll, pred);
        System.out.println("Remove evens: " + coll);

        coll = makeSet();
        Predicates.retain(coll, pred);
        System.out.println("Retain evens: " + coll);

        coll = makeSet();
        result = Predicates.collect(coll, pred);
        System.out.println("Collect evens: " + result);

        ArrayList<Integer> list = new ArrayList<>(coll);
        int i = Predicates.find(list, pred);
        System.out.println("Find first even: at index " + i);


        pred = n -> (n > 100);

        coll = makeSet();
        System.out.println("Original collection: " + coll);

        Predicates.remove(coll, pred);
        System.out.println("Remove big: " + coll);

        coll = makeSet();
        Predicates.retain(coll, pred);
        System.out.println("Retain big: " + coll);

        coll = makeSet();
        result = Predicates.collect(coll, pred);
        System.out.println("Collect big: " + result);

        list = new ArrayList<>(coll);
        i = Predicates.find(list, pred);
        System.out.println("Find first big: at index " + i);

    }

}
makeSet() Method를 사용해서 Test에 필요한 Integer Type의 Collection을 만들었습니다.

<PredicateTest main() 출력 결과>

Original collection: [17, 32, 56, 57, 83, 86, 100, 142, 999, 1899]
Remove evens: [17, 57, 83, 999, 1899]
Retain evens: [32, 56, 86, 100, 142]
Collect evens: [32, 56, 86, 100, 142]
Find first even: at index 1
Original collection: [17, 32, 56, 57, 83, 86, 100, 142, 999, 1899]
Remove big: [17, 32, 56, 57, 83, 86, 100]
Retain big: [142, 999, 1899]
Collect big: [142, 999, 1899]
Find first big: at index 7

<Java Predicate Interface / test() Method>

1. Predicate<Integer> pred = i -> (i % 2 == 0);
2. pred = n -> (n > 100);
Predicate Interface에서 test() Method의 '특정 작업'을 Lambda expression을 사용하여 정의 하였습니다.

1번의 람다식은 짝수를 판별합니다.
2번의 람다식은 100이상의 수를 판별합니다.

이렇게 pred (Predicate<Integer> 의 Instance 객체)의 test() Method의 동작을 정의하여 사용 가능합니다.

 

다음 글 부터는 Thread를 공부하고 정리해보겠습니다.

'Backend' 카테고리의 다른 글

<Backend> Java / Thread (2)  (0) 2023.11.10
<Backend> Java / Thread (1)  (2) 2023.11.09
<Backend> Java / Generic 예제문제  (2) 2023.11.07
<Backend> Java / Stack, Generic  (3) 2023.11.06
<Backend> Java / HashMap 응용  (2) 2023.11.06