Written by coh at home

[JAVA] 함수형 인터페이스와 스트림. 본문

languages/java

[JAVA] 함수형 인터페이스와 스트림.

och 2024. 2. 2. 18:52

함수형 인터페이스

자바는 람다를 함수형 인터페이스를 통해 구현한다.
인터페이스의 추상메서드가 존재할 때 우리는 해당 메서드를 오버라이드해서 사용한다.
람다는 추상메서드가 단 하나인 인터페이스에 대하여 오버라이드를 편하게 하는 방법이다.


함수형 인터페이스를 매번 구현하는 것은 귀찮은 일이므로 자바에서는 이를 제공하고 있다.
Runnable, Function, BiFunction, consumer 등등이 존재하며 Runnable에 대한 기본 코드를 한번 보자.

public class Button {
    private Runnable runnable;
    private String name;
    public Button(String name, String sound) {
        this.name = name;
        runnable = () -> System.out.println(sound);
    }

    public void onClick() {
        runnable.run();
    }
}

public class Ex01 {
    public static void main(String[] args) {
        BiFunction<String, String, Button> test = Button::new;
        Button button = test.apply("cat", "mewu");
        Runnable runnable = button::onClick;
        runnable.run();
    }
}

Button클래스의 생성자는 Button객체를 반환한다. 따라서 Bifunction을 위와같이 적용했고
만들어진 객체의 runnable은 Runnable타입이므로 생성자 안에서 람다식으로 오버라이딩하였다.

스트림

생수통이 있으면 거기에 수도꼭지를 달아서 데이터를 흘려(stream)주는 것이 바로 스트림이다.
가장 기본적인 예시를 보자.


물줄기를 필터로 한번 거르고,
모아서 정렬한 후 다시 흘려보낸다.
물줄기를 String으로 변환한 후,
전부 모아서 List로 바꾼다.

package chap9.sec4;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Ex01 {
    public static void main(String[] args) {
        List<Integer> test = new ArrayList<>(
                Arrays.asList(5, 2, 0, 8, 9, 4, 1, 7, 3, 6)
        );
        List<String> odds = test.stream() //졸졸졸
                .filter(i -> i % 2 == 1)
                .sorted(Integer::compare) // 저수지. 전부 모아놓고 sorting.
                .map(String::valueOf)// 다시 졸졸졸
                .toList();
    }
}

이것을 C스타일로 짜게 된다면 20줄 정도 될 것으로 예상한다.
하지만 스트림으로 이렇게 짧고 읽기 편하게 코드를 작성할 수 있다.


즉, 스트림은 코드의 가독성을 높여주는 도구이다.

스트림의 초기화

다음은 원시배열, 참조배열, 컬렉션, 맵, builder, 파일에서의 스트림을 만드는 방법에 대하는 방법들이다.

package chap9.sec4;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class Ex01 {
    public static void main(String[] args) {
        List<Integer> test = new ArrayList<>(
                Arrays.asList(5, 2, 0, 8, 9, 4, 1, 7, 3, 6)
        );
        List<String> odds = test.stream() //졸졸졸
                .filter(i -> i % 2 == 1)
                .sorted(Integer::compare) // 저수지. 전부 모아놓고 sorting.
                .map(String::valueOf)// 다시 졸졸졸
                .toList();

        int[] intAry = {1, 2, 3, 4, 5};
        IntStream fromPrim = Arrays.stream(intAry);
        int[] plate = fromPrim.toArray();

        Integer[] IntAry = {1, 2, 3, 4, 5};
        Stream<Integer> fromRef = Arrays.stream(IntAry);
        Object[] out = fromRef.toArray();

        // stream 생성 방법
        IntStream test1 = IntStream.of(1, 2, 3, 4, 5);
        Stream<Integer> test2 = Stream.of(1, 2, 3, 4, 5);

        // List
        List<Integer> test3 = new ArrayList<>(Arrays.asList(IntAry)); // 리스트를 만드는 배열은 원시배열은 안 된다.
        Stream fromCol = test3.stream();
        Object fromColAry = fromCol.toArray();

        //Map
        Map<String, Character> grade = new HashMap<>();
        grade.put("English", 'B');
        grade.put("Math", 'A');
        grade.put("Programming", 'A');
        var fromHashMap = grade.entrySet().stream().toArray();


        // HashMap 생성
        Map<String, Integer> map = new HashMap<>();
        map.put("One", 1);
        map.put("Two", 2);
        map.put("Three", 3);

        // entrySet()을 이용하여 맵의 모든 키-값 쌍을 얻음
        Set<Map.Entry<String, Integer>> entrySet = map.entrySet();

        // entrySet을 순회하면서 각 키-값 쌍 출력
        for (Map.Entry<String, Integer> entry : entrySet) {
            System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
        }

        Stream.Builder<Character> builder = Stream.builder();
        builder.accept('s');
        builder.accept('t');
        builder.accept('r');
        builder.accept('e');
        builder.accept('a');
        Stream<Character> withBuilder = builder.build();
        var withBuilderAry = withBuilder.toArray();

        Stream<Integer> toConcat1 = Stream.of(11, 22, 33);
        Stream<Integer> toConcat2 = Stream.of(44, 55, 66);
        Stream<Integer> withConcatMethod = Stream.concat(toConcat1, toConcat2);
        Object[] withConcat = withConcatMethod.toArray();

        Stream<Integer> withIter2 = Stream
                .iterate(0, i -> i + 2)
                .limit(10);
        var toAry1 = withIter2.toList();

        Stream<String> fromFile;
        Path path = Paths.get("src/chap9/sec4/test.txt");
        try {
            fromFile = Files.lines(path);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        var fileVar = fromFile.toArray();
    }
}

'languages > java' 카테고리의 다른 글

Collections vs Collectors  (0) 2024.10.05
[JAVA] 제네릭의 언박싱을 탐구해보자  (0) 2024.08.04
[JAVA]상속과 다형성  (1) 2023.10.30
[JAVA]static과 접근제어자.  (0) 2023.10.29
[JAVA] method  (0) 2023.10.22