-
[JAVA8] What is different things between Map and Filter in Java8?-1 / Map과 Filter 그리고 차이점에 대하여-1Backend/JAVA&JAVA8 2022. 5. 5. 13:58
안녕하세요.
오늘은 Map과 Filter 그리고 그 차이점에 대해서 알아보는 시간을 가지려 합니다.
실제로 Client 측에 Data들을 조립하여 내려줄때에 혹은 Database로 부터 Data들을 가져와서 어딘가에 담을때, 만약 List로만 담았다면 그 List를 변경할 생각을 하실텐데요.
ArrayList, HashMap과 같은 여러 데이터들을 담고있는 자료들로 부터, 특정한 조건을 주어서 원하는 무언가를 반환 하고 싶을 때에 .map() 메소드와 .filter() 메소드를 사용합니다.
저번 시간에 Optional을 살펴보며 스리슬쩍(?) 보았었죠.
바로 코드로 넘어가는게 좋을 듯 합니다. 백문이 불여일타라고 하죠?
아래와 같이 Person Class가 있다고 가정하겠습니다.
static class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public int getAge() { return this.age; } public String getName() { return this.name; } public void setAge(int age) { this.age = age; } public void setName(String name) { this.name = name; } @Override public String toString() { return super.toString(); }
그리고 이 Person Class로 구성된 List를 생성하도록 하겠습니다.
public static void main(String[] args) { List<Person> persons = Arrays.asList( new Person("harry", 30), new Person("brandon", 20), new Person("babo", 40) ); ....... }
직접 타이핑 해보시고 자신이 원하는 변수명으로 지정해보시기를 추천드립니다.
harry 라는 30살 드신 분, brandon이라는 20살 드신 분, babo 라는 40살 드신 분을 List에 모셨습니다.
그런데 이중에서, 25살 이상인 분만 한분 모시고 싶다는 가정을 세우겠습니다.
그렇다면 아래와 같이 filter 메서드를 사용하여 filtering 해주시면 됩니다.
Optional<Person> resultPerson = Optional.ofNullable(persons .stream() .filter(person -> person.getAge() > 25) .findAny() .orElse(null)); resultPerson.ifPresent(person -> System.out.println(person.getName()) );
위와 같이 코드를 작성해주시면...
(여기서 하단의 resultPerson 뒤에 ifPresent라는 메소드는, 만약 resultPerson에 값이 있다면 람다로 Person객체를 불러와서 순환시키겠다라는 뜻입니다)
출력 결과는...
harry
위와 같습니다.
filter 메소드는 리스트에서 빈값들을 솎아내는 기능으로도 활용할 수 있습니다.
아까 작성한 List를 조금만 변형시켜보겠습니다.
List<Person> persons = Arrays.asList( new Person("harry", 30), new Person("brandon", 20), new Person("babo", 40), new Person(null, 50) );
Database에서 data를 조회하였을때, java에서 의도하지않게 null인 값이 리스트 안에 섞여들어 가는 일은 흔한 일입니다.
아래와 같이 filtering 해줍니다.
List<Person> resultPersonListWithOutNull = persons .stream() .filter(person -> person.getName() != null) .collect(Collectors.toList()); resultPersonListWithOutNull.forEach(person -> { System.out.print(person.getName() + " "); }); System.out.println();
결과는 아래와 같습니다.
harry brandon babo
null 값이 제외되어진 체 깔끔하게 출력되는 모습을 보실 수 있습니다.
null에 대한 filtering을 하기 전 harry라는 결과값만 찍힌 output을 보신 분들 중에 적지 않은 분들이
"어라, babo 대신 harry가 뽑힌 이유가 뭘까? 그리고 어떠한 부분과 연관이 있을까?"
라는 생각을 하실 겁니다.
filter 메소드를 사용한뒤 주로 사용하는 메소드가 findAny() 와 findFirst()인데요.
다음 시간에는 이 두개의 메소드에 대해서 알아보는 시간을 가져볼까 합니다.
하지만 이 포스팅에서는 filter와 map이 주인공이니까 이 둘을 주인공으로 다루도록 하겠습니다.
다시 본론으로 돌아와서, filter는 위처럼 원하는 값들을 솎아내는 기능을 합니다.
filter는 반환값이 '조건에 해당하는 값' 혹은 '조건에 해당하는 값들'만 반환합니다.
위에서는 List에 대한 filtering만 실행해 보았는데요. 이번에는 Map 에 대한 filtering도 해볼까 합니다.
결론 적으로 우리는 이 포스팅에서 List와 Map에 대한 filtering을 다룰 것입니다.
(여기서 부터는 결과값을 송출시켜드리지 않으려고 합니다. 직접 해보시기를 추천드립니다. 저는 많은 도움이 되었습니다)
두가지 경우에 대해 살펴보도록 하겠습니다
1. Map으로 된 자료구조를 -> Stream화 하고 -> Filtering 하고 -> Filtering으로 나온 값을 뽑아내는 경우
[Map -> Stream -> Filtering]
2. Map으로 된 자료구조를 -> Stream화 하고 -> Filtering 하고 -> 다시 Map으로 묶는 경우
[Map -> Stream -> Filtering -> Map]
1번에 대한 코드를 살펴보겠습니다.
Map으로 된 자료구조를 -> Stream화 하고 -> Filtering 하고 -> Filtering으로 나온 값을 뽑아내는 경우
1-(1). 우선 테스트할 HashMap을 만듭니다.
private static Map<Integer, String> getTestHashMap() { Map<Integer, String> map = new HashMap<>(); map.put(1, "dokyeom"); map.put(2, "second_dokyeom"); map.put(3, "third_dokyeom"); map.put(4, "fourth_butter"); return map; }
1-(2). '원하는 값' 만을 뽑아낼 메소드를 작성합니다. '원하는 값'을 변수로 넘겨서 filtering 시켜주면 더 유용할 듯 합니다. 아래에서의 '원하는 값'이란 "second_dokyeom" 입니다.
private static String filterString(Map<Integer, String> testHashMap) { return testHashMap .entrySet() .stream() .filter(x -> "second_dokyeom".equals(x.getValue())) .map(x -> x.getValue()) .collect(Collectors.joining()); }
1-(3). 혹시나, 특정값이 아닌 여러값들을 받고 싶은 경우도 있을 것입니다. 그럴때를 대비하여 아래와 같이 메소드를 작성합니다.
private static String filterStringsWithMultipleValues(Map<Integer, String> testHashMap) { return testHashMap .entrySet() .stream() .filter(x -> { if(!x.getValue().contains("second_dokyeom") && !x.getValue().contains("fourth_dokyeom")) { return true; } else { return false; } }
1-(4). 결과값은 아래에 있는 코드를 실행시켜서 직접 확인해보시기를 추천드립니다.
System.out.println(filterString(getTestHashMap())); System.out.println(filterStringsWithMultipleValues(getTestHashMap()));
1-(5).여기서 부턴 보셔도 되고 안보셔도 되는데요. 혹시나 Generic으로 구성된 Map 에 대하여 filter를 걸고 싶은 분들도 있으실 것 같습니다. 그때에는 아래 코드를 보시면 됩니다.(Predicate class)
private static <K, V> Map<K, V> filterByValueUsingPredict(Map<K, V> map, Predicate<V> predicate) { return map .entrySet() .stream() .filter(x -> predicate.test(x.getValue())) .collect(Collectors.toMap(k -> k.getKey(), v -> v.getValue())); }
여기에서는 호출하는 곳이 중요합니다.
System.out.println(filterByValueUsingPredict(getTestHashMap(), x -> x.contains("dokyeom"))); System.out.println(filterByValueUsingPredict(getTestHashMap(), x -> x.contains("dokyeom") || x.contains("butter"))); System.out.println(filterByValueUsingPredict(getTestHashMap(), x -> x.length() <= 10));
2번에 대한 코드를 살펴보겠습니다.
Map으로 된 자료구조를 -> Stream화 하고 -> Filtering 하고 -> 다시 Map으로 묶는 경우
private static Map<Integer, String> collectString(Map<Integer, String> testHashMap) { return testHashMap .entrySet() .stream() .filter(x -> x.getKey() == 2) .collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue())); }
위와 같이 작성해주시면 됩니다. 의외로 간단하죠?
return에서 반환해주는 맨 마지막 줄인 collect 부분을 신경써주시면 됩니다.
Collectors 클래스에 대해서는 추후 또 다루도록 하겠습니다.
헉헉.. 포스팅이 길어지는 것 같아서 Map에 대한 부분은 다음 포스팅으로 넘기도록 하겠습니다.
긴 글 읽어주셔서 감사합니다.
'Backend > JAVA&JAVA8' 카테고리의 다른 글
[JAVA8] What is different things between findAny and findFirst? / findAny와 findFirst의 차이점에 대하여 (0) 2022.05.05 [JAVA8] What is different things between Map and Filter in Java8?-2 / Map과 Filter 그리고 차이점에 대하여-2 (0) 2022.05.05 [JAVA8] About Optional-2 / Optional에 대하여-2 (0) 2022.05.05 [JAVA8] About Optional-1 / Optional에 대하여-1 (0) 2022.05.05 [JAVA8] About Stream 스트림에 대하여 (0) 2022.05.05