Java/Java

스트림의 메서드

마손리 2023. 3. 11. 01:32

스트림에 대해 공부하던중 몇몇 유용해보이는 메서드들이 있어 이에대해 포스팅하게 됬다.

 

orElse()

List<Integer> list = Arrays.asList();

// 컴파일 오류 발생
Double value = list.stream()
        .mapToDouble((a)->a)
        .average();

// 런타임 오류 발생
Double value = list.stream()
        .mapToDouble((a)->a)
        .average()
        .getAsDouble();

위와 같은 코드를 작성하면 컴파일 에러가 발생한다. 이유는 average()를 이용해 평균값을 구할때 입력값이 아예 없으면 즉 빈 리스트를 불러와 평균값을 구할수가 없기 때문이다. 해당 리스트에 숫자형 데이터 "0"이라도 존재 한다면 "0"을 리턴하지만 빈 리스트에서는 "0"조차도 값을 구할수 없기 때문이다.

 

하지만 orElse()메서드를 사용하면 해결된다.

Double value = list.stream()
        .mapToDouble((a)->a)
        .average()
        .orElse(0);

orElse()를 이용하여 값이 아예 없는 '무' 가 될경우 0이라는 기본값을 주도록 설정할수 있다.

 

 

Comparable, Comparator 클래스

public class Main {

    public static void main(String[] args) {
        List<Human> list = Arrays.asList(
                new Human("qwe",23),
                new Human("asd",24),
                new Human("zxc",21),
                new Human("rty",23),
                new Human("fgh",23)
        );
       
        // 객체 안, 문자형 정렬
        list.stream()
                .sorted(Comparator.comparing((obj)->obj.getName()))
                .sorted(Comparator.comparing(Human::getName).reversed()); // 위와 같은 표현식이지만 reversed()메서드로 역순정렬

        list.stream()
                .sorted((obj1,obj2)->obj2.getName().compareTo(obj1.getName()));
				//compareTo를 활용한 역순정렬 이며
                //해당 객체의 클래스(Human)에 Comparable클래스를 상속받아
                //직접 compareTo메서드를 오버라이딩해줄수도 있다.
    }
}

class Human {
    private String name;
    private int age;

    public Human(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() { return name; }
    public int getAge() { return age; }
}

 

 

 

 

굳이 Stream이 아니어도 모든 정렬 메서드에서 사용이 가능하며, 숫자형 데이터는 더 쉬우므로 생략...

 

 

Collectors.groupingBy

.collect(Collectors.groupingBy())

groupingBy 메서드를 활용하면 데이터들을 그룹화하여 Map으로 타입을 변환시켜준다.

( .collect()메서드는 해당 데이터들을 담을 컬렉션이나 맵으로 변환할때 사용한다.)

 

public class Main {
    public static void main(String[] args) {
    	//데이터 리스트
        List<Human> list = new ArrayList<>();
        list.add( new Human("김철수",23,"남자"));
        list.add( new Human("이영희",24,"여자"));
        list.add(new Human("개똥이",21,"남자"));
        list.add( new Human("박대기",23,"남자"));
        list.add( new Human("김세희",23,"여자"));

		// 사람들의 나이를 기준으로key를 생성하고 분류하여 해당 나이에 맞는 객체들을 묶어줌
        Map<Integer,List<Human>> groupingBy = list.stream().collect(Collectors.groupingBy((a)->a.getAge()));
        
        // grouping된 데이터를 출력하기위해 Set으로 타입 변환(Map 타입으로는 stream불가)
        Set<Map.Entry<Integer,List<Human>>> entrySet = groupingBy.entrySet();

		// 위의 데이터 Set을 이용하여 스트림을 생성하고 각 아이템들에 접근한뒤 출력
        entrySet.stream().forEach((entry)->{
            System.out.printf("Entry { Key = %s, Values = ",entry.getKey());
             entry.getValue().forEach((a)->a.print());
            System.out.println("}");
        });
    }

}

class Human {
    private String name;
    private int age;
    private String gender;

    public Human(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
    public String getName() { return name;}
    public String getGender() { return gender; }
    public int getAge() { return age; }
    
    public void print(){
        System.out.printf("[ name: %s, age: %d, gender: %s ], ", this.name, this.age, this.gender);
    }
}

보통 HashMap등 데이터 Map을 만들때는 각 데이터가 가지고 있는 고유한 값을 Key로 사용하지만 groupBy의 경우 이름 그대로 데이터들을 하나의 기준에 맞게 묶어주는 역할을 하기에 각 데이터들이 가지고 있는 값들중 고유하지 않은, 즉 중복된 특정한 값을 Key로 사용해준다. 

위 코드의 출력

 

 

Grouping을 위한 스태틱메서드생성

public class Main {
    public static void main(String[] args) {
        List<Human> list = new ArrayList<>();
        list.add( new Human("김철수",23,"남자"));
        list.add( new Human("이영희",24,"여자"));
        list.add(new Human("개똥이",21,"남자"));
        list.add( new Human("박대기",23,"남자"));
        list.add( new Human("김세희",23,"여자"));

        Map<Integer,List<Human>> groupingBy = Mapping.groupingBy(list, Mapping.Options.NAME);
        Set<Map.Entry<Integer,List<Human>>> entrySet = Mapping.entrySet(groupingBy);

        Mapping.print(entrySet);


    }

}

class Mapping{
    enum Options {AGE,NAME,GENDER}
    private static Options category;
    public static Map groupingBy(List<Human> list, Options option){

        category = option;

        return list.stream().collect(Collectors.groupingBy((a)->{
            if(option.equals(Options.NAME)) return a.getName();
            if(option.equals(Options.GENDER)) return a.getGender();
            return a.getAge();
        }));
    }
    public static Set entrySet(Map<Integer,List<Human>> groupingBy){
        return groupingBy.entrySet();
    }
    public static void print(Set<Map.Entry<Integer,List<Human>>> entrySet){
        System.out.printf("Map groupingBy %s {\n",category);
        entrySet.stream().forEach((entry)->{
            System.out.printf("Entry { Key = %s, Values = ",entry.getKey());
            entry.getValue().forEach((a)->a.print());
            System.out.println("}");
        });
        System.out.println("}");
    }
}

위와 같이 grouping을 위한 클래스와 스태틱 메서드들을 만들어 보던중 궁금한 것들이 생겨서 실험을 해보던중 몇가지를 알게되었다.

(다음 포스트에 계속...)

'Java > Java' 카테고리의 다른 글

스레드 (Thread)  (0) 2023.03.12
자바 가상 머신(Java Virtual Machine)  (0) 2023.03.11
스트림 (Stream)  (0) 2023.03.10
파일 입출력 (InputStream, OuputStream, FileReader, FileWriter, File)  (0) 2023.03.09
람다(Lambda)  (2) 2023.03.09