java 8 정리3

Java 정리 2021. 5. 17. 22:18

인프런 강의 6일차.

 - 더 자바, Java 8 (백기선 강사님)

 

1. 인터페이스 기본 메소드와 스태틱 메소드 2

 - Iterable의 기본 메소드

   -> forEach()

   -> spliterator()

 

 - Collection의 기본 메소드(Collection은 Iterable의 상속받는 클래스이니 사실상 Collection = Iterable과 같다)

   -> stream() / parallelStream()

   -> removeIf(Predicate)

   -> spliterator()

 

 - Comparator의 기본 메소드

   -> reversed()

   -> thenComparing()

   -> static reverseOrder() / naturalOrder()

   -> static nullsFirst() / nullsLast()

   -> static comparing()

 

 

package me.whiteship.java8to11;

import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;

public class App {

    public static void main(String[] args) {
        /*GreetingInterface greetingInterface = new DefaultGreeting("park");
        greetingInterface.printName();              //park 출력
        greetingInterface.printNameUpperCase();     //PARK 출력

        GreetingInterface.printAnything();      //Interface의 static 메소드 바로 사용*/

        List<String> name = new ArrayList<>();
        name.add("park");
        name.add("dong");
        name.add("hyeon");
        name.add("kim");

        //case1. foreach lambda
        name.forEach(s -> {
            //System.out.println(s);
        });

        //case2. foreach method reference
        //name.forEach(System.out::println);

        Spliterator<String> spliterator = name.spliterator();
        //case3. spliterator 사용(name 배열을 순회하면서 출력한다)
        //tryAdvance = hasNext와 같은 역할
        //while(spliterator.tryAdvance(System.out::println));


        /* spliterator.trySplit()를 사용한 split 시 배열에 대해 trySplit을 진행한 뒤 tryAdvance를 수행해야 한다.
        즉 아래 코드는 오류가 발생한다.
        Spliterator<String> spliterator = name.spliterator();
        while(spliterator.tryAdvance(System.out::println));

        Spliterator<String> spliterator1 = spliterator.trySplit();  //name 배열에 대해 split 진행
        while(spliterator1.tryAdvance(System.out::println));
        --------------------------------------------------------------
        //정상 동작 쿼리
        Spliterator<String> spliterator = name.spliterator();
        Spliterator<String> spliterator1 = spliterator.trySplit();  //name 배열에 대해 split 진행
        while(spliterator.tryAdvance(System.out::println));
        while(spliterator1.tryAdvance(System.out::println));
        */

        //name 배열에 대해 UppserCase실행 후 filer를 걸어서 P로 시작하는 값만 읽어서 count
        name.stream().map(String::toUpperCase)
                    .filter(s -> s.startsWith("P"))
                    .count();

        //k로 시작하는 문자열 제거
        name.removeIf(s -> s.startsWith("k"));
        name.forEach(System.out::println);
        /*park
        dong
        hyeon*/

        //case1. 문자열 역순으로 소팅
        name.sort(String::compareToIgnoreCase);
        name.forEach(System.out::println);
        /*dong
        hyeon
        park
        */

        //case2. 문자열 역순으로 소팅(Comparator 사용)
        Comparator<String> compareToIgnoreCase = String::compareToIgnoreCase;
        name.sort(compareToIgnoreCase.reversed());
        name.forEach(System.out::println);
        /*park
        hyeon
        dong
        */

        //case3. 문자열 역순으로 소팅 reversd() 사용 후 thenComparing으로 추가 비교
        //name.sort(compareToIgnoreCase.reversed().thenComparing());
        name.forEach(System.out::println);


    }

}

 

 

2. 스트림 API

 - Stream : sequence of elements supporting sequential and parallel aggregate operations

   -> 데이터를 담고 있는 저장소(컬렉션)이다.

   -> Function in nature, 스트림이 처리하는 데이터 소스를 변경하지 않는다.

   -> 스트림으로 처리하는 데이터는 오직 한번만 처리한다.

   -> 무제한일 수도 있다. (Sort Circuit 메소드를 사용해서 제한할 수 있다.)

   -> 중개 오퍼레이션은 근본적으로 lazy하다.

   -> 손쉽게 병렬처리할 수 있다.

 

 - 스트림 파이프라인

   -> 0 또는 다수의 중개 오퍼레이션(intermediate operation)과 한개의 종료 오퍼레이션(terminal operation)으로 구성.

   -> 스트림의 데이터 소스는 오직 터미널 오퍼레이션을 실행할 때에만 처리한다.

 

 - 중개 오퍼레이션

   -> Stream을 리턴한다.

   -> Stateless / Statefull 오퍼레이션으로 더 상세하게 구분할 수도 있다. (대부분은 Stateless지만 distinct나 sorted처럼 이전 이전 소스 데이터를 참조해야 하는 오퍼레이션은 Statefull 오퍼레이션이다)

   -> filter, map, limit, skip, sorted, ...

 

 - 종료 오퍼레이션

   -> Stream을 리턴하지 않는다.

   -> collect, allMatch, count, forEach, min, max, ...

 

List<String> name = new ArrayList<>();
        name.add("park");
        name.add("dong");
        name.add("hyeon");
        name.add("kim");

        //Stream<String> stringStream
        name.stream().map((s) -> {
            System.out.println(s);      //map은 중개 오퍼레이션이기 때문에 터미널 오퍼레이션이 오기전까지 실행되지 않는다. 즉 해당 sout은 출력되지 않는다!
            return s.toUpperCase();
        }); //해당 상태는 종료 오퍼레이션 없이 끝난 스트림이다.(선언만 된 상태이다)

        List<String> collect = name.stream().map((s) -> {
            System.out.println(s);      //map은 중개 오퍼레이션이기 때문에 터미널 오퍼레이션이 오기전까지 실행되지 않는다. 즉 해당 sout은 출력되지 않는다!
            return s.toUpperCase();
        }).collect(Collectors.toList());//종료 오퍼레이션인 collect 추가했기 때문에 처리 진행

        //return이 upperCase이므로 sout 당시는 소문자가 출력되고, return값인 collect 변수 출력 시 대문자가 출력된다.
        name.forEach(System.out::println);      //대문자 출력

        //병렬 스트림
        List<String> collect1 = name.parallelStream().map((s)->{
            System.out.println(s + " " + Thread.currentThread().getName()); //ForkJoinPool을 통해 다른 thread에서 실행됨을 확인 가능
            return s.toUpperCase();
        }).collect(Collectors.toList());
        collect1.forEach(System.out::println);

 

 

package me.whiteship.java8to11;

import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class App {

    public static void main(String[] args) {
        List<OnlineClass> springClasses = new ArrayList<>();
        springClasses.add(new OnlineClass(1, "spring boot", true));
        springClasses.add(new OnlineClass(2, "spring data jpa", true));
        springClasses.add(new OnlineClass(3, "spring mvc", false));
        springClasses.add(new OnlineClass(4, "spring core", false));
        springClasses.add(new OnlineClass(5, "rest api development", false));

        List<OnlineClass> javaClasses = new ArrayList<>();
        javaClasses.add(new OnlineClass(6, "The Java, Test", true));
        javaClasses.add(new OnlineClass(7, "The Java, Code manipulation", true));
        javaClasses.add(new OnlineClass(8, "The Java, 8 to 11", false));

        List<List<OnlineClass>> keesunEvents = new ArrayList<>();
        keesunEvents.add(springClasses);
        keesunEvents.add(javaClasses);

        System.out.println("spring 으로 시작하는 수업");
        springClasses.stream()
                .filter(oc -> oc.getTitle().startsWith("spring"))
                .forEach(oc -> System.out.println(oc.getId()));

        System.out.println("close 되지 않은 수업");
        springClasses.stream()
                .filter(Predicate.not(OnlineClass::isClosed))//  filter(oc -> !oc.isClosed())와 같은 의미이다.
                .forEach(oc -> System.out.println(oc.getId()));

        System.out.println("수업 이름만 모아서 스트림 만들기");
        //map이라는 중개 오퍼레이션을 사용해야함
        springClasses.stream()
                .map(oc -> oc.getTitle())       //input은 onlineClass로 들어오나 output은 다른 type으로 변경가능
                //.forEach(s -> System.out.println(s));   //getTitle이 String이기 때문에 들어온 String 출력
                .forEach(System.out::println);          //method preference

        System.out.println("두 수업 목록에 들어있는 모든 수업 아이디 출력");
        //keesunEvents는 리스트 2개를 모아놓은 리스트이고, 이 2개를 합쳐서 1개의 스트림으로 만들어야한다. -> Flat 시킨다
        keesunEvents.stream()
                .flatMap(Collection::stream)        //리스트를 flat 시켜 1개의 스트림으로 만들음
                .forEach(oc -> System.out.println(oc.getId())); //input이 collection stream으로 들어감


        System.out.println("10부터 1씩 증가하는 무제한 스트림 중에서 앞에 10개 빼고 최대 10개 까지만");
        //Stream의 iterator를 가지고 구현 가능
        Stream.iterate(10, i -> i + 1)      //10부터 1씩 증가하는 무제한 스트림 (중개 오퍼레이션이기 때문에 iterate만 있어도 별다른 실행이 되지 않는다.
                .skip(10)
                .limit(10)
                .forEach(System.out::println);

        System.out.println("자바 수업 중에 Test가 들어있는 수업이 있는지 확인");
        //Stream의 Match로 구현 가능
        boolean test = javaClasses.stream().anyMatch(oc -> oc.getTitle().contains("Test"));
        System.out.println(test);

        System.out.println("스프링 수업 중에 제목에 spring이 들어간 제목만 모아서 List로 만들기");
        //case1. filter 먼저 수행 (filter에서 onlineClass로 비교 수행)
        List<String> spring = springClasses.stream()
                .filter(oc -> oc.getTitle().contains("spring"))  //filter을 먼저 해도 되고, map을 먼저 해도 됨. 다만 어떤 것을 먼저 하느냐에 따라 지나가는 타입이 달라지므로 구현에 주의!
                .map(OnlineClass::getTitle)
                .collect(Collectors.toList());

        //case2. map 먼저 수행 (filter에서 String 으로 비교 수행)
        List<String> spring1 = springClasses.stream()
                .map(OnlineClass::getTitle)
                .filter(t -> t.contains("spring"))
                .collect(Collectors.toList());
    }

}

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

java 8 정리6  (0) 2021.05.21
java 8 정리5  (0) 2021.05.20
java 8 정리4  (0) 2021.05.19
java 8 정리2  (0) 2021.05.13
java 8 정리1  (0) 2021.05.12