ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java μ‘μš©] 5. λžŒλ‹€μ‹κ³Ό ν•¨μˆ˜, 슀트림
    Dev/Java 2023. 3. 26. 23:44
    728x90

    πŸ“˜ μ‘μš© 5μž₯ λžŒλ‹€μ‹κ³Ό ν•¨μˆ˜, 슀트림

    1κΈ‰ 객체

    πŸ’‘
    1κΈ‰ κ°μ²΄λž€, λ³€μˆ˜μ— λŒ€μž… κ°€λŠ₯ν•œ 객체λ₯Ό 1κΈ‰ 객체 (first class object) 라고 ν•œλ‹€.

    λŒ€ν‘œμ  1κΈ‰ 객체 : κ°’, μΈμŠ€ν„΄μŠ€, λ°°μ—΄

    ν•¨μˆ˜ (function)

    πŸ’‘
    Java8에 μΆ”κ°€λœ κ°œλ… : ν•¨μˆ˜λ„ 1κΈ‰ 객체둜 μ·¨κΈ‰ λœλ‹€.

    ν•¨μˆ˜λž€, μž…λ ₯에 λŒ€ν•΄ 처리 ν›„ 좜λ ₯ν•˜λŠ” 것

    y = 2x + 3

    λ©”μ„œλ“œλ₯Ό λ³€μˆ˜μ— λŒ€μž…ν•˜μ—¬ μ‚¬μš©ν•˜λŠ” 예

    import java.util.function.IntBinaryOperator;
    
    public class Main {
        public static int add(int x, int y) {
            return x + y;
        }
    
        public static void main(String[] args) {
    				// 미리 μ •μ˜λœ μΈν„°νŽ˜μ΄μŠ€
    				// μœ„μ— μ •μ˜ν•œ add() λ©”μ„œλ“œλ₯Ό func μΈν„°νŽ˜μ΄μŠ€ λ³€μˆ˜μ— λŒ€μž… ν–ˆλ‹€.
            IntBinaryOperator func = Main::add;
            int result = func.applyAsInt(5, 3);
            System.out.println("5 + 3 = " + result);
        }
    }
    πŸ’‘
    μž…μΆœλ ₯ νƒ€μž…λ§Œ κ°™λ‹€λ©΄, λ©”μ„œλ“œλ₯Ό λ³€μˆ˜μ— λŒ€μž…ν•˜λŠ” 것이 κ°€λŠ₯ν•˜λ‹€. μœ„ μ½”λ“œμ—μ„œλŠ” 미리 μ •μ˜λœ IntBinaryOperator μΈν„°νŽ˜μ΄μŠ€ λ³€μˆ˜μ— μž„μ˜λ‘œ μ •μ˜ν•œ add()ν•¨μˆ˜λ₯Ό λŒ€μž… ν–ˆλ‹€.

    :: (Method Reference)

    πŸ’‘
    :: λŠ” λ©”μ„œλ“œ 레퍼런슀(Method Reference)λ₯Ό λ‚˜νƒ€λ‚΄λŠ” μ—°μ‚°μžμ΄λ‹€. λ©”μ„œλ“œ λ ˆνΌλŸ°μŠ€λŠ” λ©”μ„œλ“œλ₯Ό μ°Έμ‘°ν•˜λŠ” 객체λ₯Ό μƒμ„±ν•˜λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό 생성할 λ•Œ μ‚¬μš©λœλ‹€. λ©”μ„œλ“œ 레퍼런슀λ₯Ό μ‚¬μš©ν•˜λ©΄ λΆˆν•„μš”ν•œ λžŒλ‹€ ν‘œν˜„μ‹μ„ μ œκ±°ν•˜μ—¬ 가독성을 ν–₯μƒμ‹œν‚€κ³ , μ½”λ“œμ˜κΈΈμ΄λ₯Ό 쀄일 수 μžˆλ‹€. 예λ₯Ό λ“€μ–΄, Math 클래슀의 abs λ©”μ„œλ“œλ₯Ό λžŒλ‹€ ν‘œν˜„μ‹μœΌλ‘œ λ‚˜νƒ€λ‚΄λ©΄ λ‹€μŒκ³Ό κ°™λ‹€. Function<Integer, Integer> absFunc = (x) -> Math.abs(x); λ©”μ„œλ“œ 레퍼런슀λ₯Ό μ‚¬μš©ν•˜λ©΄ 이 μ½”λ“œλ₯Ό λ‹€μŒκ³Ό 같이 κ°„λ‹¨ν•˜κ²Œ λ‚˜νƒ€λ‚Ό 수 μžˆλ‹€. Function<Integer, Integer> absFunc = Math::abs; :: μ—°μ‚°μžλŠ” λ©”μ„œλ“œ 레퍼런슀λ₯Ό μ°Έμ‘°ν•˜λŠ” 객체λ₯Ό μƒμ„±ν•˜λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ μΈμŠ€ν„΄μŠ€ λ₯Ό 생성할 λ•Œ μ‚¬μš©λœλ‹€. λ©”μ„œλ“œ λ ˆνΌλŸ°μŠ€λŠ” λ‹€μ–‘ν•œ ν˜•νƒœλ‘œ μ‚¬μš©λ  수 있으며, λ©”μ„œλ“œ 이름과 클래슀 이름, μƒμ„±μž 이름 등을 ν•¨κ»˜ μ‚¬μš©ν•˜μ—¬ ν‘œν˜„λœλ‹€.

    λ©”μ„œλ“œμ™€ ν•¨μˆ˜μ˜ 차이

    πŸ’‘
    - λ©”μ„œλ“œλŠ” ν΄λž˜μŠ€μ— μ†ν•˜κ³  클래슀λ₯Ό μ‘°μž‘ν•˜κΈ° μœ„ν•œ μΌμ’…μ˜ ν•¨μˆ˜μ΄λ‹€. - λ©”μ„œλ“œλŠ” 이름이 μžˆμ§€λ§Œ, ν•¨μˆ˜μ—κ²Œ 이름은 μ€‘μš”ν•˜μ§€ μ•Šλ‹€.

    public static int add(int x, int y) {
    		return x + y;
    }
    
    public static int λ”ν•˜κΈ°(int a, int b) {
    		return a + b;
    }
    πŸ’‘
    ν•¨μˆ˜λŠ” 이름은 λ‹€λ₯΄μ§€λ§Œ inputκ³Ό output이 κ°™μœΌλ―€λ‘œ, λ™μΌν•œ ν•¨μˆ˜λΌ λ³Ό 수 μžˆλ‹€.

    ν•¨μˆ˜ μ €μž₯용 μΈν„°νŽ˜μ΄μŠ€ μ„ μ–Έ

    πŸ’‘
    좔상 λ©”μ„œλ“œκ°€ 1개인(SAM : Single Abstract Method) μΈν„°νŽ˜μ΄μŠ€λŠ” ν•¨μˆ˜ μ €μž₯ μš©λ„λ‘œ μ‚¬μš© κ°€λŠ₯ν•˜λ‹€

    ν•¨μˆ˜ μ €μž₯용 λ²”μš© API

    πŸ’‘
    Javaμ—μ„œ 자주 μ‚¬μš©ν•  것 같은 ν•¨μˆ˜ μ €μž₯용 λ²”μš© API 제곡

    β†’ 직접 SAM μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ •μ˜ν•  μˆ˜λ„ μžˆμ§€λ§Œ, 미리 제곡된 SAM μΈν„°νŽ˜μ΄μŠ€ APIλ₯Ό ν™œμš©ν•΄λ³΄μž.

    μ„€λͺ…

    Predicate<T> : <T>의 값을 input으둜 λ°›κ³ , 쑰건에 따라 boolean 값을 좜λ ₯ν•˜λŠ” ν•¨μˆ˜λ₯Ό μ €μž₯ν•  λ•Œ ν•΄λ‹Ή μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.

    λžŒλ‹€μ‹ (Lambda Expression)

    πŸ’‘
    Lambda 식 ν™œμš©ν•˜μ—¬ ν•¨μˆ˜ λ‚΄μš©μ„ λ°”λ‘œλ°”λ‘œ μ •μ˜ν•΄μ„œ μ‚¬μš©ν•  수 μžˆλ‹€.
    interface MyFuction {
        int call(int a, int b);
    }
    
    public class Main {
        
        public static void main(String[] args) {
    				// Lambda 식을 ν™œμš©ν•œ ν•¨μˆ˜ μ •μ˜ 및 μΈν„°νŽ˜μ΄μŠ€ 객체 λŒ€μž…
            MyFuction func = (int a, int b) -> {
                return a + b;
            };
            
            int result = func.call(5, 3);
            System.out.println("5 + 3 = " + result);
    		}
    }

    λžŒλ‹€μ‹μ˜ ν‘œκΈ°λ²•

    정석적인 Lambda expression ν‘œκΈ°

    IntToDoubleFunction func = (int a) -> {
    		return a * 3.14;
    };

    μž…λ ₯ νƒ€μž… μƒλž΅ κ°€λŠ₯

    IntToDoubleFunction func = (a) -> {
    		return a * 3.14;
    };
    πŸ’‘
    μ–΄μ°¨ν”Ό interface에 μ§€μ •λ˜μ–΄ 있기 λ•Œλ¬Έμ— μƒλž΅μ΄ κ°€λŠ₯ν•˜λ‹€! interfaceλ‚΄ μ§€μ •λœ νƒ€μž… μ™Έμ—λŠ” 값을 쀄 수 μ—†λ‹€.

    μž…λ ₯ 값이 1개일 경우 μ†Œκ΄„ν˜Έ μƒλž΅ κ°€λŠ₯

    IntToDoubleFunction func = a -> {
    		return a * 3.14;
    };

    ν•¨μˆ˜μ˜ λ‚΄μš©μ΄ 리턴 밖에 없을 경우 μ€‘κ΄„ν˜Έ 및 return ν‚€μ›Œλ“œ μƒλž΅ κ°€λŠ₯

    IntToDoubleFunction func = a -> a * 3.14;

    슀트림(Stream)

    πŸ’‘
    슀트림(Stream)μ΄λž€? - Java Stream은 Java Collection Framework의 μš”μ†Œλ“€μ„ μ²˜λ¦¬ν•˜λŠ”λ° μ‚¬μš©λœλ‹€. - ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ° κ°œλ…μ„ λ„μž…ν•˜μ—¬ μ½”λ“œμ˜ κ°„κ²°μ„±κ³Ό 가독성이 ν–₯μƒλœλ‹€. (참고❗) _ 데이터 μž…μΆœλ ₯에 κ΄€λ ¨λœ streamκ³ΌλŠ” λ³„κ°œμ΄λ‹€!! Stream의 νŠΉμ§•
    1. μš”μ†Œλ“€μ„ λ³€κ²½ν•˜μ§€ μ•ŠλŠ”λ‹€. λŒ€μ‹ , μš”μ†Œλ“€μ˜ 원본 데이터 μ†ŒμŠ€λ‘œλΆ€ν„° μƒˆλ‘œμš΄ μŠ€νŠΈλ¦Όμ„ μƒμ„±ν•œλ‹€.
    1. ν•œ λ²ˆμ— ν•˜λ‚˜μ˜ μš”μ†Œλ§Œ μ²˜λ¦¬ν•œλ‹€.
    1. 쀑간 처리 단계와 μ΅œμ’… 처리 λ‹¨κ³„λ‘œ λ‚˜λ‰œλ‹€. 쀑간 처리 λ‹¨κ³„μ—μ„œλŠ” 필터링, λ§€ν•‘, μ •λ ¬ λ“±μ˜ 처리λ₯Ό μˆ˜ν–‰ν•˜κ³ , μ΅œμ’… 처리 λ‹¨κ³„μ—μ„œλŠ” κ²°κ³Όλ₯Ό μˆ˜μ§‘ν•œλ‹€.
    1. 병렬 처리λ₯Ό μ§€μ›ν•œλ‹€.

    πŸ’‘
    ν•¨μˆ˜λ₯Ό κ°’μœΌλ‘œ μ·¨κΈ‰ν•  λ•Œμ˜ 이점 Java 8에 μΆ”κ°€λœ ν•¨μˆ˜λ₯Ό 닀루기 μœ„ν•œ λ²”μš© API Stream을 μ‚¬μš©ν•˜λ©΄, μ’€ 더 ν•¨μˆ˜μ μΈ 사고λ₯Ό κ°€μ§€κ³  κ°œλ°œν•  수 μžˆλ‹€. β‡’ ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°

    πŸ’‘
    Java Stream의 λ©”μ†Œλ“œ
    1. filter(): μš”μ†Œλ“€μ„ 필터링
    1. map(): μš”μ†Œλ“€μ„ λ³€ν™˜
    1. sorted(): μš”μ†Œλ“€μ„ μ •λ ¬
    1. distinct(): μ€‘λ³΅λœ μš”μ†Œλ“€μ„ 제거
    1. limit(): μš”μ†Œλ“€μ˜ 개수λ₯Ό μ œν•œ
    1. forEach(): μš”μ†Œλ“€μ„ 반볡 처리
    1. collect(): μš”μ†Œλ“€μ„ μˆ˜μ§‘
    1. reduce(): μš”μ†Œλ“€μ„ ν•˜λ‚˜λ‘œ ν•©μΉ˜κΈ°

    Stream 예제 μ—°μŠ΅ 1 - ArrayList μ›μ†Œ μ²˜λ¦¬ν•˜κΈ°

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import java.util.function.Predicate;
    
    public class Main2 {
    
        public static void main(String[] args) {
            // 슀트림 μ‹€μŠ΅
            List<Integer> nums = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6));
            
    				// 일반적인 for문을 ν†΅ν•œ 짝수 좜λ ₯
            for (int i = 0; i < nums.size(); i++) {
                if (nums.get(i) % 2 == 0) {
                    System.out.println(nums.get(i) + 1);
                }
            }
    
            // μŠ€νŠΈλ¦Όμ„ ν™œμš©ν•œ 좜λ ₯
            nums.stream().forEach((num) -> {
                System.out.println(num); //μž…λ ₯이 Integer이고, 리턴이 void
            });
            
            // μœ„ μ½”λ“œ μΆ•μ•½
            nums.stream().forEach(num -> System.out.println(num));
            
            // ν•œλ²ˆ 더 μΆ•μ•½
            nums.stream().forEach(System.out::println);
            
    				// ν•„ν„° μ‚¬μš© - μ£Όμ–΄μ§„ 쑰건에 λ§€μΉ˜λ˜λŠ” κ²ƒλ§Œ 좜λ ₯ν•˜λŠ” 법
            // Map을 μ‚¬μš©ν•˜λ©΄ List의 νƒ€μž…μ„ λ³€ν™”μ‹œν‚¬ 수 μžˆλ‹€.
            nums.stream().filter((Integer num) -> num % 2 == 0) // 짝수만 λ‚¨κ²Œ ν•˜κΈ°
    			               .map((num) -> num + "번") // λ³€ν™˜ν•  λ•Œ map μ‚¬μš© (<T>) -> (<R>)
    		                 .forEach((num) -> System.out.println(num + 1));
        }
    }

    Stream 예제 μ—°μŠ΅ 2 - β€˜λ°•β€™μ”¨ κ°€μ Έμ˜€κΈ°

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import java.util.stream.Collectors;
    
    public class Main2 {
        
        // 'λ°•'씨 κ°€μ Έμ˜€κΈ° - stream을 ν™œμš©ν•œ lambda 식 ν‘œν˜„
        public static List<String> getParkListStream(List<String> names) {
            return names.stream().filter(name -> name.startsWith("λ°•")).collect(Collectors.toList());
        }
        
        // 'λ°•'씨 κ°€μ Έμ˜€κΈ° - κΈ°μ‘΄ for문을 ν™œμš©ν•œ ν‘œν˜„
        public static List<String> getParkList(List<String> names) {
            List<String> results = new ArrayList<>();
    
            for (String name : names) {
                if (name.startsWith("λ°•")) {
                    results.add(name);
                }
            }
            return results;
        }
    
    
        public static void main(String[] args) {
            List<String> names = new ArrayList<>();
    				names.add("λ°•1");
            names.add("λ°•2");
            names.add("이1");
            names.add("κΉ€1");
            names.add("λ°•3");
    
            List<String> parks = getParkList(names);
            List<String> parks2 = getParkListStream(names);
            
            System.out.println(parks);
            System.out.println(parks2);
        }
    }

    πŸ’‘
    Stream은 λͺ¨λ“  리턴 νƒ€μž…μ΄ stream νƒ€μž…μ΄λ‹€. 그렇기에 ν•œ 쀄 μ½”λ”©μœΌλ‘œ .() ν•  수 μžˆλŠ” 것이닀. -> λ©”μ„œλ“œ 체이닝 forEachλŠ” 맨 λ§ˆμ§€λ§‰μ—λ§Œ 올 수 μžˆλ‹€.
    πŸ’‘
    μ§€κΈˆ κΉŒμ§€λŠ” λ¦¬μŠ€νŠΈμ— 각 데이터λ₯Ό μ ‘κ·Όν•΄ 직접 가져와 μ²˜λ¦¬ν–ˆλ‹€. Stream을 μ‚¬μš©ν•˜λ©΄, κΈ°μ‘΄ forλ¬Έμ—μ„œ forEach둜 λŒ€μ²΄ν•˜κ³ , 리슀트 값을 forEach(λžŒλ‹€μ‹)을 톡해 각 데이터가 Stream ν˜•νƒœλ‘œ μ€„μ€„νžˆ λžŒλ‹€μ‹ ν•¨μˆ˜λ₯Ό 거쳐 좜λ ₯λ˜λŠ” ν˜•νƒœμ΄λ‹€. μ΄λŸ¬ν•œ 방식을 ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ΄λΌ λ³Ό 수 μžˆλ‹€.

    for vs stream

    πŸ’‘
    Stream은 μ»¬λ ‰μ…˜μ„ λ‹€λ£¨λŠ”λ° μžˆμ–΄μ„œ for문보닀 νš¨μœ¨μ μ΄λ‹€. Stream은 병렬 μ²˜λ¦¬μ— μœ λ¦¬ν•˜ λ©°, 데이터λ₯Ό ν•„μš”ν•œ λΆ€λΆ„λ§Œ μ²˜λ¦¬ν•˜κΈ° λ•Œλ¬Έμ— μ„±λŠ₯이 μ’‹μ•„μ§„λ‹€. λ˜ν•œ, Stream은 κ°„κ²°ν•œ μ½”λ“œ 둜 μ»¬λ ‰μ…˜μ„ λ‹€λ£° 수 μžˆμ–΄μ„œ 가독성이 μ’‹μ•„μ§„λ‹€.


    πŸ“μ—°μŠ΅ 문제

    5-1

    package com.pkd.Exam;
    
    public class Utils {
        public static boolean isOdd(int n) {
            return n % 2 == 1;
        }
    
        public static String addNamePrefix(boolean male, String name) {
            if (male == true) {
                return "Mr." + name;
            }
            return "Ms." + name;
        }
    }
    package com.pkd.Exam;
    
    public interface Func1 {
        boolean call(int n);
    }
    package com.pkd.Exam;
    
    public interface Func2 {
        String call(boolean b, String s);
    }

    5-2

    package com.pkd.Exam;
    
    public class Main {
    
        public static void main(String[] args) {
            Func1 func1 = num -> num % 2 == 1;
            
            Func2 func2 = (male, name) -> {
                if (male == true) {
                    return "Mr." + name;
                }
                return "Ms." + name;
            };
        }
    }
    πŸ’‘
    Func1의 μƒλž΅ : 1) μž…λ ₯ νƒ€μž…, 2) μž…λ ₯ κ°’ 1개 일 λ•Œ μ†Œκ΄„ν˜Έ, 3) μ€‘κ΄„ν˜Έ, 리턴 Func2의 μƒλž΅ : 1) μž…λ ₯ νƒ€μž…



    Uploaded by N2T

    728x90
    λ°˜μ‘ν˜•

    λŒ“κΈ€

Keydi's Tistory