JAVA8 Stream 2

김건우·2022년 12월 12일
2

JAVA 8

목록 보기
2/2
post-thumbnail

Stream의 병렬처리

병렬 처리란 멀티코어 환경에서 하나의 작업을 분할해 각각의 코어가 병렬적으로 처리하는 것이다. 자바 8 부터는 병렬 스트림과 포크/조인 프레임워크를 사용하면 쉽게 병렬처리가 가능하다.

동시성과 병렬성

공통점은 둘 다 동작방식이 멀티 스레드라는 점이지만 목적은 다르다.

  • 동시성
    멀티 작업을 위해 멀티 스레드가 번갈아가면서 실행한다.

  • 병렬성
    병렬성은 멀티 작업을 하기 위해 멀티 코어를 이용해 동시에 실행하는 성질이다.

병렬 스트림

병렬 스트림은 각각의 스레드에서 처리할 수 있도록 스트림 요소를 여러 청크로 분할한 스트림이다. 따라서 병렬 스트림을 이용하면 멀티코어 프로세서가 각각의 청크를 처리하도록 할당이 가능해진다.

 List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
 Integer result = list.parallelStream().reduce(0,Integer::sum);
 System.out.println("result = " + result); // <- 36 출력

병렬 스트림은 각각의 스레드에서 처리할 수 있도록 스트림 요소를 여러 청크로 분할한 스트림이다. 때문에 병렬 스트림을 이용하면 멀티 코어 프로세서가 각각의 청크를 처리하도록 할당이 가능해진다. parallelStream()을 호출하면 컬렉션에서 바로 병렬 스트림을 리턴한다.

순차스트림과 병렬스트림의 switch

순차 스트림에 parallel()메소드를 호출하면 기존 스트림을 병렬로 변경이 가능하고, 병렬 스트림에 sequential()메소드를 호출하면 순차 스트림으로 변경할 수 있다.
이 메소드를 호출하면 내부적으로 병렬로 수행해야 함을 의미하는 불리언(boolean) 플래그가 설정되게 된다. 메소드를 통해 연산 마다 병렬 실행과 순차 실행을 수행할 지 제어할 수 있게 된다.

stream.parallel() // <-병렬 스트림으로
    .map() 
    .sequential() // <-순차 스트림으로
    .reduce(); 

스트림의 max() ,average()

mapToInt() : 스트림을 IntStream으로 변환해주는 메서드다.

public static void main(String[] args) {
		//sturdent : 이름 / 점수
        List<Student> list = Arrays.asList(
                new Student("홍길동",82),
                new Student("김남준",90),
                new Student("주몽",100),
                new Student("박혁거세",80),
                new Student("온조",70)
        );

    
        int max = list.stream()
                .mapToInt(Student::getAge)
                .max().getAsInt();
        System.out.println("max = " + max);

        double average = list.stream()
                .mapToInt(Student::getAge)
                .average().getAsDouble();
        System.out.println("average = " + average);
    }
  • 출력문 🔽
max = 100
average = 84.4

배열로 부터 스트림 얻기

🌈tip

Collectors.joining("/") : "/" 로 나뉘어서 출력해준다. 여기서 강력한 기능은 마지막은 "/"가 출력이 안된다. 매개변수에 다른 기호나 문자를 넣어주면 그에 맞게 나뉘어서 출력된다.

   String[] stringArray = {"나", "아빠", "엄마"};
        Stream<String> nameStream = Arrays.stream(stringArray);
        String collect = nameStream.collect(Collectors.joining("/"));
        System.out.println("collect = " + collect);

int[] intArray = {1, 2, 3, 4, 5};
IntStream intStream = Arrays.stream(intArray);
intStream.forEach(a -> System.out.print(a + ","));
  • 출력문 🔽
나/아빠/엄마  <- 이 부분을 잘보면 마지막엔 Collectors.joining("/")로 마지막에 "/" 가 없다.
1,2,3,4,5,

스트림의 sorted()

sorted()를 사용할 때 주의점

  • 객체 요소일 경우에는 Comparable을 구현하지 않으면 첫번째 sorted() 메소드를 호출하면 ClassCastException이 발생
  • 객체 요소가 Compatable을 구현하지 않았거나, 구현 했다하더라도 다른 비교 방법으로 정렬하려면 Comparator를 매개값으로 갖는 두번째 sorted() 메소드를 사용해야 한다.

Comparator 인터페이스

Comparator는 함수적 인터페이스이므로 다음과 같이 람다식으로 매개값을 작성할 수 있다.

sorted((a, b) -? { ... })
  • 중괄호 { } 안에는 a와 b를 비교해서 a가 작으면 음수, 같으면 0, a가 크면 양수를 리턴하는 코드를 작성

정렬 코드

오름차순의 3가지 방법

  • 객체 요소가 Comparable를 구현한 전제 과정이 있음
sorted(); // 1
sorted((a, b) -> a.compareTo(b)); // 2
sorted(Comparator.naturalOrder()); // 3

내림차순의 2가지 방법

  • 객체 요소가 Comparable를 구현한 전제 과정이 있음
sorted((a, b) -> b.compareTo(a)); // 1
sorted(Comparator.reverseOrder()); // 2

sorted 예제

  • Comparable의 인터페이스의 compareTo메서드를 재정의 해줘야한다

compareTo메서드를 재정의해준 Student클래스

@Getter @AllArgsConstructor
public class Student implements Comparable<Student>{

    private String name;
    private Integer score;

    @Override
    public int compareTo(Student o) {
        return Integer.compare(score, o.score);;
    }
}

위(오름차순) / 아래(내림차순)

 public static void main(String[] args) {

        List<Student> studentList = Arrays.asList(
                new Student("손흥민", 90),
                new Student("박지성", 88),
                new Student("차범근", 92)
        );
        
        studentList.stream()
                .sorted()
                .forEach(student ->{
                    String name = student.getName();
                    int score = student.getScore();
                    System.out.println("이름 : " + name + " / 점수 : " + score);
                });

        System.out.println("----위(오름차순) / 아래(내림차순)----");

        studentList.stream()
                .sorted(Comparator.reverseOrder())
                .forEach(student ->{
                    String name = student.getName();
                    int score = student.getScore();
                    System.out.println("이름 : " + name + " / 점수 : " + score);
                });

    }
  • sorted() 오름차순 / 내림차순 출력문 🔽
이름 : 박지성 / 점수 : 88
이름 : 손흥민 / 점수 : 90
이름 : 차범근 / 점수 : 92
----위(오름차순) / 아래(내림차순)----
이름 : 차범근 / 점수 : 92
이름 : 손흥민 / 점수 : 90
이름 : 박지성 / 점수 : 88

매칭(Mathching) Stream

반환 타입은 Boolean타입(true/false)

  • allMatch() :모든 요소들이 매개값으로 주어진 Predicate의 조건을 만족하는지 조사
  • anyMatch() : 최소한 한 개의 요소가 매개값으로 주어진 Predicate의 조건을 만족하는지 조사
  • noneMatch() : 모든 요소들이 매개값으로 주어진 Predicate의 조건을 만족하지 않는지 조사
public static void main(String[] args) {
    int[] intArray = {2, 4, 6};

    boolean result = Arrays.stream(intArray).allMatch(a -> a % 2 == 0);
    System.out.println("모두 2의 배수인가? " + result);

    result = Arrays.stream(intArray).anyMatch(a -> a % 3 == 0);
    System.out.println("3의 배수가 있는가? " + result);

    result = Arrays.stream(intArray).noneMatch(a -> a % 3 == 0);
    System.out.println("3의 배수가 없는가? " + result);
  }
  • 출력문 🔽
모두 2의 배수인가? true
3의 배수가 있는가? true
3의 배수가 없는가? false

Collect() 수집 최종 처리

최종 처리 기능으로 요소들을 수집 or 그룹핑하는 기능이 있다.

  • 필터링 또는 매핑된 요소들로 구성된 새로운 컬렉션을 생성한다.
  • 요소들을 그룹핑하고, 집계를 할 수 있다.
  • enum 타임으로 성별을 추가하고 수정한 클래스
@Data  
@AllArgsConstructor
public class Student implements Comparable<Student>{

    private String name;
    private Integer score;
    private Sex sex;

    @Override
    public int compareTo(Student o) {
        return Integer.compare(score, o.score);
    }
    //성별 enum
    public enum Sex{
        MALE,FEMALE
    }

}
  • collect()를 사용하여 남학생과 여학생을 별도의 List컬렉션으로 생성하는 stream문
 public static void main(String[] args) {


        List<Student> totalList = Arrays.asList(
                    new Student("홍길동", 10, Student.Sex.MALE),
                    new Student("홍길순", 12, Student.Sex.FEMALE),
                    new Student("김남", 10, Student.Sex.MALE),
                    new Student("김여", 8, Student.Sex.FEMALE),
                    new Student("김여", 8, Student.Sex.FEMALE)
            );

        List<Student> maleList = totalList.stream()
                    .filter(s -> s.getSex() == Student.Sex.MALE)
                    .collect(Collectors.toList());
            maleList.forEach(s -> System.out.println(s.getName()));

        System.out.println("---------------위(남자)/아래(여자)---------------");

        Set<Student> femaleSet = totalList.stream()
                    .filter(s -> s.getSex() == Student.Sex.FEMALE)
                    .collect(Collectors.toCollection(HashSet::new));
            		femaleSet.forEach(s -> System.out.println(s.getName()));
        }
    }
  • 출력문 🔽
홍길동
김남
---------------위(남자)/아래(여자)---------------
홍길순
김여
  • 2가지 방법으로 HashSet으로 수집가능하다..
	//1
   .collect(Collectors.toCollection(HashSet::new));
    //2
   .collect(Collectors.toSet());

Collectors.toCollection(람다식)으로 수집하는 방법

//List나 Map이 아닌 컬렉션으로의 변환
Stream<String> stream3 = Stream.of("1", "2", "3", "4", "5");
ArrayList<String> streamToArrayList = 
stream3.collect(Collectors.toCollection(() -> new ArrayList<>()));
System.out.println("streamToArrayList = " + streamToArrayList);
profile
Live the moment for the moment.

0개의 댓글