Cohe

15. Operator, Stream 본문

개발 언어/JAVA

15. Operator, Stream

코헤0121 2024. 3. 27. 14:51
728x90
  • Operator : 매개 변수 0, 리턴0 (연산 결과)
    • 연산하는 것
    • Function의 하위 인터페이스로 보통 매개변수값을 연산하고 그 결과를 리턴하는 경우 사용
    인터페이스 추상 메서드
    BinaryOperator<T> T apply(T t1, T t2)
    UnaryOperator<T> T apply(T t)
    xxxBinaryOperator xxx applyAsXXX(xxx,xxx)
    xxxUnaryOperator xxx applyAsXXX(xxx)
  • predicate : 매개 변수 0, 리턴0 (boolean), 추상 메서드를 test라는 이름으로 가지고 있따.인터페이스 리턴(boolean)
    Predicate<T> boolean test(T t)
    BiPredicate boolean test(T t, U u)
    xxxPredicate boolean test(xxxx)

Stream

  • 스트림 : 여러 값들을 가지고 있는 배열이나 컬렉션등을 for문이 아닌 함수형 인터페이스를 이용해서 반복 처리할 수 있는 기능
  • 필수는 아니지만 가독성 좋은 코드를 생성하기 위해서 알아둬야 함.
  • 스트림 객체 생성 : build() 메서드 이용하기
    • builder()메서드로 Builder 객체 생성 이후에 add() 메서드로 리턴타입이 Builder 객체이므로 메서드 체이닝 가능
  • 스트림 사용 : 배열, 컬렉션, 빌더를 사용할 수 있다.
  • generate()메서드 이용하기
    • 람다에서 Supplier<T> 인터페이스를 이용하여 값을 추가 생성합니다.
  • 스트림은 람다(함수형 인터페이스)를 활용하여 내부 반복자를 이용 시간과 코드의 양을 줄임, 또한 스트림을 통해서 간단하게 병렬 처리가 가능

스트림의 처리 단계!

  1. 생성 : 스트림 인스턴스 생성
  2. 가공 : 필터링과 맵핑 등 원하는 결과를 만들어가는 중간 작업
  3. 결과 : 최종적으로 결과를 얻어내는 작업
  • 외부 반복자 vs 내부 반복자
    • 외부 반복자 : 컬렉션 내의 요소를 반복문을 통해 하나씩 읽어 처리하는 방식 (for문)
    • 내부 반복자 : 스트림의 for-each 메서드를 람다식을 사용해서 기술하는 방식을 의미 (stream)


  • 외부 파일에서 스트림 생성하기
    • Files.find(Path, int BiPredicatem FileVisitOption) , Files.list(Path)
      • 반환타입 : Stream<Path>
    • Files.lines(Path, Charset), BufferedReader.lines()
      • 반환타입 : Stream<String>
package G_java;
import java.util.stream.Stream;
import java.util.Arrays;
import java.util.List;

public class G08_StreamEx {
    public static void main(String[] args) {
        //배열을 이용한 스트림 생성
        String[] arr = new String[]{
            "a", "b", "c", "d","e","f"
        };

        Stream<String> stream1 = Arrays.stream(arr);
        stream1.forEach(s->System.out.print(s+" "));
        System.out.println();

        Stream<String> stream2 = Arrays.stream(arr, 2, 5); //배열의 일부를 추출해서 객체 생성
        stream2.forEach(s->System.out.print(s+" "));
        System.out.println();

        //문자열 배열을 컬렉션 프레임워크로 만들어서 스트림 만들기
        List<String> list = Arrays.asList(arr);

        //List 객체를 stream()를 이용. Stream 객체 생성
        Stream<String> stream3 = list.stream();
        stream3.forEach(s->System.out.print(s));

        //스트림 객체 생성 : build() 메서드 이용하기
        Stream stream4 = Stream.builder() //집어넣는 개수에 따라서 달라짐!! 따로 limit이 필요치 않다!
            .add("무궁화")
            .add("삼천리")
            .add("화려강산")
            .add("대한사람")
            .add("현영이")
            .build();
        stream4.forEach(s->System.out.println(s+" "));
        System.out.println();


        //스트림 객체 생성 : 2.generate()메서드 이용하기
        //람다에서 Supplier<T> 인터페이스를 이용하여 값을 추가 생성합니다.

        Stream<String> Stream5 = Stream.generate(()->"애국가").limit(10); //limit이 없으면 끝이 안난다.
        Stream5.forEach(s->System.out.println(s+" "));

        //스트림 객체 생성 : 3. iterate() 메서드 이용하기
        Stream<Integer> stream6 = Stream.iterate(1, n->n+1).limit(10);  //시작 값 1->10까지
        stream6.forEach(s-> System.out.println(s+" "));
    }

}

 

가공단계

  • 가공 중간 처리 단계
  • 필터링 : filtering
    • Stream 내의 요소를 걸러내는 기능을 말함
    • 메소드
      1. distinct() : 중복 제거
      2. filter() : 조건에 맞는 요소를 선택(boolean 결과에 따른 검출)
    • Stream
      • Steam
      • IntStream
      • LongStream
      • DoubleStream
package G_java;

import java.util.Arrays;
import java.util.List;

public class G11_FilteringEx {
    public static void main(String[] args) {
        //list 객체 생성하기
        List<String> list = Arrays.asList("홍길동", "김유신","홍길동", "이순신 ","홍길동", "유관순","홍길동", "김유신" );

        //distinct() 메소드로 중복 제거 후 내부 반복자로 출력

        System.out.println("distinct()");
        list.stream().distinct().forEach(s->System.out.println(s+" "));
        System.out.println();

        //"홍으로 시작하는 문자열로 필터링 후 내부 반복자로 출력
       
        System.out.println("filter()");
        list.stream().filter(n->n.startsWith("홍"))
            .forEach(e->System.out.println(e+" "));

        //distinct()와 filter()를 동시에 사용
        System.out.println("distinct()+filter()");
       
        list.stream().distinct().filter(n->n.startsWith("홍")).forEach(e->System.out.println(e+" "));

    }
}
  • 매핑 : mapping 연결해줌
    • 컬렉션 프레임워크에 맵과 유사한 기능을 한다. 즉, key: value와 같이 묶어주는 것을 맵핑이라고 한다.
    • 맵핑은 스트림의 데이터를 매개변수로 받아서 가공처리 후 새로운 스트림을 만들어 리턴한다.
    • 데이터 변환을 위한 기능
    • 메서드
      • flatMapXXX() 메서드
        • 다른 타입의 요소를 가진 스트림을 생성 및 반환
        • 리턴 타입
          • Stream <R>
          • DoubleStream
          • IntStream
          • LongStream
      • mapXXX()
      • asDoubleStream()
      • asLongStream()
      • box()
package G_java;

import java.util.Arrays;
import java.util.List;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;

public class G12_mappingEx {

    public static void main(String[] args) {
        //flatMapXXX() 메서드

        //문자열을 공백으로 분리해서 매핑
        List<String> list1 = Arrays.asList("동백물과", "백두산이", "마르고 닳도록");
        list1.stream().flatMap(data -> Arrays.stream(data.split(" "))).forEach(word->System.out.println(word));

        //문자열을 , 로 분리해서 double 자료형으로 반환하여 맵핑
        List<String> list2 = Arrays.asList("1.1,2.2,3.3","4.4,5.5,6.6"); //이걸 더블 스트링으로 바꿀거에용
        DoubleStream dsr = list2.stream().flatMapToDouble(data->{
            String[] strArr = data.split(",");
            double[] dArr = new double[strArr.length];
            for (int i = 0;i<dArr.length;i++){
                dArr[i] = Double.parseDouble(strArr[i].trim());
            }
            return Arrays.stream(dArr);
        });
        dsr.forEach(n-> System.out.println(n));
        System.out.println();




        //---------------------여기부터 공부 다시 하기------------------

        //문자열을 , 로 분리해서 int 자료형으로 변화해서 매핑
        List<String> list3 = Arrays.asList("1, 2, 3","4, 5, 6");
        IntStream isr = list3.stream().flatMapToInt(data -> {
            String[] strArr = data.split(",");
            int[] intArr = new int[strArr.length];
            for(int i = 0; i< strArr.length; i++) {
                intArr[i] = Integer.parseInt(strArr[i].trim());
            }
            return Arrays.stream(intArr);
        });
        isr.forEach(s -> System.out.println(s));

        //mapXXX() 메서드 : 요소를 새로 구성해서 새로운 스트림을 리턴
        List<String> list4 = Arrays.asList("동해물과", "백두산이","마르고 닳도록");

        System.out.println("함수적 인터페이스 방식");
        list4.stream().mapToInt(String::length)
            .forEach(len -> System.out.println(len));
        // - asDoubleStream, asLongStream, boxed
        // asDoubleStream : IntStream, LongStream을 DoubleStream으로 형변환
        // asLongStream : IntStream을 LongStream으로 형변환
        // boxed : IntStream, LongStream, DoubleStream을 각가 Stream<Integer>
        //     , Stream<Long>, Stream<Double>로 형변환
        int intArr[] = {10, 20, 30, 40, 50, 60};

        // double타입의 요소를 갖는 DoubleStream으로 형변환
        Arrays.stream(intArr).asDoubleStream()
                        .forEach(d -> System.out.println(d));
        System.out.println();

        //int타입의 요소를 갖는  Stream<Integer>으로 형변환
        Arrays.stream(intArr).boxed()
                        .forEach(i -> System.out.println(i.getClass()));

    }
}
  • 정렬 : sorting
package G_java;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

public class G13_SortingEx {
    public static void main(String[] args) {
            /*
     *  Stream의 중간 단계에서 sorted메서드를 사용하여 순서를 변경할 수 있음.
     *  일반적인 객체를 정렬하기 위해서는 Comparable 인터페이스를 구현한 클래스 객체만 정렬
     *  가능합니다.
     *
     */

     List<String> list = Arrays.asList("홍길동", "김유신","이순신","유관순");

     System.out.println("기본 정렬");
     list.stream().sorted().forEach(System.out::println);  // 메서드 참조 방식
     System.out.println();

     System.out.println("역순 정렬");
     list.stream().sorted(Comparator.reverseOrder())
                           .forEach(System.out::println);  // 메서드 참조 방식
     System.out.println();

     //일반 객체 정렬 테스트
     Shape s1 = new Rectangle(10, 3);
     Shape s2 = new Circle(10);
     Shape s3 = new Rectangle(20, 2);
     Shape s4 = new Circle(11);

     List<Shape> list2 = Arrays.asList(s1, s2, s3, s4);

     System.out.println("오름차순 정렬");
     list2.stream().sorted().forEach(System.out::println);

     System.out.println("내림차순 정렬");
     list2.stream().sorted((a, b) -> b.compareTo(a) - a.compareTo(b))
                 .forEach(System.out::println);

     System.out.println("내림차순 정렬2");
     list2.stream().sorted(Comparator.reverseOrder())
                 .forEach(System.out::println);

        // 둘레를 기준으로 정렬
        System.out.println("정렬하지 않고 출력");
        list2.stream().forEach(System.out::println);

        System.out.println("둘레(length()) 순으로 정렬");
        System.out.println("함수적 인터페이스로 구현");
        list2.stream().sorted(new Comparator<Shape>() {
            public int compare(Shape o1, Shape o2) {
                return (int)(o1.length() - o2.length());
            };
        }).forEach(System.out::println);

        System.out.println("람다표현식을 이용해서 둘레순으로 정렬");
        list2.stream().sorted((a,b) -> (int)(b.length() - a.length()))
                    .forEach(System.out::println);
 
    }

}
abstract class Shape implements Comparable<Shape> {
    //필드
    int x, y;

    //생성자
    Shape() {
        this(0, 0);
    }

    Shape(int x, int y) {
        this.x = x;
        this.y = y;
    }

    //추상 메서드
    abstract double area();
    abstract double length();

    //일반 메서드
    public String getLocation() {
        return "x: "+x+", y: "+y;
    }

    @Override
    public int compareTo(Shape o) {
        return (int)(this.area() - o.area());
    }
}

class Rectangle extends Shape {

    // 필드
    int w, h;

    //생성자
    public Rectangle() {
        this(1, 1);
    }

    public Rectangle(int w, int h) {
        this.w = w;
        this.h = h;
    }

    @Override
    double area() {
        return (w*h);
    }

    @Override
    double length() {
        return (w+h) * 2;
    }

    @Override
    public String toString() {
        return "넓이 : "+this.area();
    }

}

class Circle extends Shape {

    //필드
    double r;

    //생성자
    public Circle() {
        this(1);
    }

    public Circle(double r) {
        this.r = r;
    }

    @Override
    double area() {
        return (r * r) * Math.PI;
    }

    @Override
    double length() {
        return (r * 2) * Math.PI;
    }

    @Override
    public String toString() {
        return "넓이는 : "+this.area();
    }

}

 

  • 그룹핑 : grouping
package G_java;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class G17_collect_groupBy {
    // collect() 메서드는 스트림의 요소들을 필터링하거 매핑한 후에 새로운 객체로 생성
    // groupingBy() 메서드는 Map객체를 생성할 수 있습니다.

    public static void main(String[] args) {
       
        Shape s1 = new Rectangle(10, 3);
        Shape s2 = new Circle(10);
        Shape s3 = new Rectangle(20, 2);
        Shape s4 = new Circle(11);

        List<Shape> list = Arrays.asList(s1, s2, s3, s4);

        //요소가 Rectangle 객체인 경우 collect 메서드로 List로 변환
        List<Shape> rectList = list.stream()
                .filter(s -> s instanceof Rectangle).collect(Collectors.toList());
        rectList.stream().forEach(f -> System.out.println(f));
        System.out.println();

        // 요소가 Rectangle 객체인 경우 collect 메서드로 Set으로 변환
        Set<Shape> rectSet = list.stream()
             .filter(s -> s instanceof Rectangle).collect(Collectors.toSet());
        rectSet.stream().forEach(System.out::println); //메소드 접근 방법 -> 하나의 값을 넘겼을 때 그 함수 값을 실행시키세요!

        //groupingBy() Map 객체 생성
        //key-value 값으로 정의
        try {
            // 객체 타입으로 그룹핑 (Rectangle, Circle)
            Map<Object, List<Shape>> map = list.stream() //obj -> 객체
                .collect(Collectors.groupingBy(f -> f.getClass()));
            System.out.println("사각형 출력");
            map.get(Class.forName("Rectangle")).stream()
                    .forEach(f -> System.out.println(f));

            map.get(Class.forName("Circle")).stream()
                    .forEach(f -> System.out.println(f));
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

    }
}

'개발 언어 > JAVA' 카테고리의 다른 글

17. Network, 서버 만들기!  (0) 2024.03.28
16. ParallelStream, Thread  (0) 2024.03.27
14 람다식  (0) 2024.03.25
13 객체 정렬을 위한 객체 간 크기 비교, 제너릭 , File 입출력  (0) 2024.03.21
12 JAVA API  (0) 2024.03.20