JiwonDev

#4. μžλ°” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€

by JiwonDev

# ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ (Functional Interface)

  • 좔상 λ©”μ†Œλ“œλ₯Ό λ”± ν•˜λ‚˜λ§Œ 가지고 μžˆλŠ” μΈν„°νŽ˜μ΄μŠ€
  • SAM (Single Abstract Method) μΈν„°νŽ˜μ΄μŠ€
  • @FuncationInterface μ• λ…Έν…Œμ΄μ…˜μ„ 가지고 μžˆλŠ” μΈν„°νŽ˜μ΄μŠ€

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€(Functional Interface) λŠ” κΈ°λ³Έ μžλ°”μ—λ„ μ‚¬μš©ν–ˆλ˜ κ°œλ…μΈλ°, 좔상 λ©”μ„œλ“œλ₯Ό λ”± ν•˜λ‚˜λ§Œ 가지고 μžˆλŠ” μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ˜λ―Έν•œλ‹€. (λ‹€λ₯Έ λ©”μ„œλ“œμ˜ κ°œμˆ˜λŠ” 상관없닀.) 이λ₯Ό SAM (Single Abstract Method) μΈν„°νŽ˜μ΄μŠ€ 이라고 λΆ€λ₯΄κΈ°λ„ ν•œλ‹€.

public interface Hello {
    void doSomething();
    // void doSomething2(); 좔상화 λ©”μ„œλ“œκ°€ 2개 이상이면 ν•¨μˆ˜ν˜•μ΄ μ•„λ‹ˆλ‹€.
    
    static void printName(){
        System.out.println("λ‹€λ₯Έ λ©”μ„œλ“œμ˜ μˆ˜λŠ” 상관없닀.");
    }
}

 

μ΄λ ‡κ²Œ λ§Œλ“  μΈν„°νŽ˜μ΄μŠ€λŠ” 기쑴의 μžλ°”μ—μ„œ λ‹€μŒκ³Ό 같은 읡λͺ…ν•¨μˆ˜λ₯Ό μž‘μ„± ν•  수 μžˆμ—ˆλ‹€.

public class Main {
    public static void main(String[] args) { 
    // 기쑴의 읡λͺ… λ‚΄λΆ€ 클래슀
        Hello hello = new Hello(){
            @Override
            public void doSomething(){
                System.out.println("Hello");
            }
        };
    }
}

 


# λžŒλ‹€ ν‘œν˜„μ‹(Lambda Expressions)

이λ₯Ό λ‹€λ₯Έ ν•¨μˆ˜ν˜• μ–Έμ–΄(python, Js)처럼 ν™”μ‚΄ν‘œ ν‘œν˜„μ‹μ˜ 인라인 μ½”λ“œλ‘œ λ°”κΎΌ 것이 μžλ°”μ˜ λžŒλ‹€ ν‘œν˜„μ‹ (Lambda Expressions) μ΄λ‹€. ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ„ 곡뢀해봀닀면, μ΅μˆ™ν•œ λͺ¨μ–‘μ˜ μ½”λ“œμΌ 것이닀.

  • ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“œλŠ” λ°©λ²•μœΌλ‘œ 쓰일 수 μžˆλ‹€.
  • μ½”λ“œλ₯Ό 쀄일 수 μžˆλ‹€.
  • λ©”μ†Œλ“œ λ§€κ°œλ³€μˆ˜, 리턴 νƒ€μž…, λ³€μˆ˜λ‘œ λ§Œλ“€μ–΄ μ‚¬μš©ν•  μˆ˜λ„ μžˆλ‹€.
public class Main {
    public static void main(String[] args) {
    // λžŒλ‹€ ν‘œν˜„μ‹. 단 ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ—λ§Œ μ‚¬μš© κ°€λŠ₯ν•˜λ‹€.
        Hello hello = () -> System.out.println("Hello");
        hello.doSomething(); // hello μžμ²΄λŠ” 객체이지 ν•¨μˆ˜κ°€ μ•„λ‹˜μ„ μœ μ˜ν•˜μž. 
    }
}

# λ©”μ„œλ“œ 레퍼런슀, μƒμ„±μž 레퍼런슀

ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ—μ„œλŠ” ν•¨μˆ˜ 자체λ₯Ό νŒŒλΌλ©”νƒ€λ‘œ 쀄 수 μžˆλ‹€. μžλ°”λŠ” λͺ¨λ“  것이 클래슀둜 이루어져 μžˆκΈ°μ— ν•¨μˆ˜λ₯Ό λ°”λ‘œ 전달 ν•  μˆ˜λŠ” μ—†κ³ , λ©”μ„œλ“œ 레퍼런슀(::method)λ₯Ό λΉ„μŠ·ν•˜κ²Œ κ΅¬ν˜„ ν•  μˆ˜μžˆλ‹€.

// 이 두 μ½”λ“œλŠ” 같은 λ™μž‘μ„ ν•œλ‹€.
// setFunction(System.out::println);
// setFunction(msg -> System.out.println(msg));

import java.util.function.UnaryOperator;

public class Main {
    public static void main(String[] args) {
        Greeting greeting = new Greeting();
        UnaryOperator<String> toStr = greeting::toString;; // Greeting.toString() ν•¨μˆ˜
    }
}
import java.util.Arrays;
import java.util.Comparator;

public class Main {
    public static void main(String[] args) {
        String[] names = {"hello","bye","see you"};
        // 이미 μ‘΄μž¬ν•˜λŠ” ν•¨μˆ˜ μ‚¬μš©
        Arrays.sort(names, String::compareToIgnoreCase);
        // 직접 λžŒλ‹€ν•¨μˆ˜λ‘œ μ •μ˜
        Arrays.sort(names, (n1,n2)-> n1.toString().compareTo(n2.toString()));
        
        
        // 읡λͺ… 클래슀둜 같은 λ‚΄μš©μ„ κ΅¬ν˜„ν•œ μ½”λ“œ, Java8 μ΄μ „μ˜ 방식
        Arrays.sort(names, new Comparator<String>() {
            @Override
            public int compare(String n1, String n2) {
                return n1.toString().compareTo(n2.toString());
            }
        });
    }
}

 

같은 λ¬Έλ²•μœΌλ‘œ λ©”μ„œλ“œ 이름 λŒ€μ‹  ::new λ₯Ό μ΄μš©ν•˜λ©΄ μ•„μ˜ˆ ν•΄λ‹Ή 클래슀의 μƒˆλ‘œμš΄ 객체λ₯Ό μƒμ„±ν•˜λŠ” ν•¨μˆ˜λ₯Ό λ§Œλ“€ 수 μžˆλ‹€.

Function<String, Greeting> createGreeting = Greeting::new; // μƒμ„±μž ν•¨μˆ˜ μ •μ˜
Greeting myGreeting = createGreeting.apply("myClassName"); // μ‹€ν–‰(객체 생성)

// label λ°°μ—΄μ˜ 각각의 μš”μ†Œμ— μ ‘κ·Ό(map)ν•˜μ—¬ stream을 μƒμ„±ν•˜κ³ , 이λ₯Ό μ΄μš©ν•΄ Button 객체 배열을 λ§Œλ“ λ‹€. 
// 슀트림(Stream)은 λ‚˜μ€‘μ— μžμ„Έν•˜κ²Œ μ„€λͺ…ν•  μ˜ˆμ •μ΄λ‹ˆ, 일단 λ„˜μ–΄κ°€μž
Stream<Button> stream = labels.stream().map(Button::new);
List<Button> buttons = stream.collect(Collectors.toList());

// ::new λ₯Ό μ΄μš©ν•˜μ—¬ button 배열을 μ΄ˆκΈ°ν™” ν•˜λŠ” 방법
Button[] buttons = stream.toArray(Button[]::new)

 

 


# μžλ°”μ—μ„œμ˜ ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°

즉 ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ™€ λžŒλ‹€λŠ” μžλ°”μ—μ„œ ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ„ μ§€μ›ν•˜λŠ” κΈ°λŠ₯인데, μš”μ•½ν•˜λ©΄ λ‹€μŒκ³Ό κ°™λ‹€.

  • ν•¨μˆ˜λ₯Ό First class object둜 μ‚¬μš©ν•  수 μžˆλ‹€.
  • 순수 ν•¨μˆ˜ (Pure function) : SideEffectκ°€ μ—†λ‹€. 같은 μž…λ ₯μ—λŠ” 같은 좜λ ₯을 보μž₯ν•œλ‹€.
  • κ³ μ°¨ ν•¨μˆ˜ (Higher-Order Function) : ν•¨μˆ˜λ₯Ό μž…λ ₯, λ°˜ν™˜ κ°’μœΌλ‘œ μ‚¬μš© ν•  수 μžˆλ‹€.
  • 값이 λΆˆλ³€μ„±μ„ 가진닀.

λ¬Όλ‘  μˆœμˆ˜ν•¨μˆ˜ 원칙을 κΉ¨κ³  JS ν΄λ‘œμ € 처럼 클래슀 λ‚΄μ˜ λ³€μˆ˜λ‚˜ μ™ΈλΆ€μ˜ 값을 가져와 μ‚¬μš©ν•  μˆ˜λ„ μžˆλ‹€. ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ—μ„œ μΆ”μ²œν•˜λŠ” 방법이 μ•„λ‹ˆμ§€λ§Œ, μ‚¬μš©ν•œλ‹€κ³ ν•΄μ„œ 무쑰건 λ‚˜μœ μ½”λ“œμΈ 건 μ•„λ‹ˆλ‹€.

public class Main {
    public static void main(String[] args) {
        int baseNumber = 10;
        Hello hello = () -> System.out.println(baseNumber + 5);
    }
}

 

참고둜 이 λžŒλ‹€ν‘œν˜„μ‹μ„ 읡λͺ…ν•¨μˆ˜λ‘œ μ •μ˜ν•˜λ©΄ μ•„λž˜μ™€ κ°™λ‹€.

public class Main {
    public static void main(String[] args) {
        int baseNumber = 10;

        // 이 μ½”λ“œλŠ” μœ„μ˜ λžŒλ‹€ν‘œν˜„μ‹κ³Ό λ™μΌν•œ μ½”λ“œμ΄λ‹€.
        Hello hello = new Hello() {
            @Override
            public void doSomething() {
                System.out.println(baseNumber + 5);
            }
        };
    }
}

 


# ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ API

java.util.function μ—μ„œ 레퍼런슀λ₯Ό λ³Ό 수 μžˆλ‹€. 맀번 ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ 클래슀λ₯Ό λ§Œλ“€κΈ° λ²ˆκ±°λ‘œμš°λ―€λ‘œ, 자주 μ‚¬μš©ν•˜λŠ” ν˜•νƒœμ˜ ν•¨μˆ˜λ“€μ„ μ‰½κ²Œ λ§Œλ“€ 수 있게 ν•΄μ£ΌλŠ” API 이닀. λ‹Ήμ—°ν•œ κ²ƒμ΄μ§€λ§Œ, 이λ₯Ό λžŒλ‹€κ°€ μ•„λ‹Œ 읡λͺ…ν•¨μˆ˜λ‘œ κ΅¬ν˜„ν•˜λ©΄ 가독성이 맀우 떨어진닀.

 

λ‹¨μˆœνžˆ ν‘œλ‘œ 봀을 λ•ŒλŠ” μ–΄λ €μ›Œ 보일 수 μžˆλŠ”λ°, μ•„λž˜μ— μžˆλŠ” μ½”λ“œλ₯Ό 보면 μ‰½κ²Œ 이해 ν•  수 μžˆλ‹€. 참고둜 ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ° λ‹΅κ²Œ, API λ©”μ„œλ“œλ₯Ό μ΄μš©ν•΄ μ—¬λŸ¬ ν•¨μˆ˜λ₯Ό μ‘°ν•©ν•΄μ„œ ν•˜λ‚˜λ‘œ ν•©μΉ  μˆ˜λ„ μžˆλ‹€.

// Bμ‹€ν–‰ ν›„ λ°˜ν™˜κ°’ 전달, 이후 Aμ‹€ν–‰ 즉 ν•¨μˆ˜μ˜ 합성이닀.
newFunc = funcA.compose(funcB)

// Aμ‹€ν–‰ ν›„ Bμ‹€ν–‰. κ·Έλƒ₯ λ‹¨μˆœνžˆ 연달아 μ‹€ν–‰ν•˜λŠ” 것 뿐이닀.
newFunc = fucnA.andThen(funcB)

 

μ’…λ₯˜ νŠΉμ§• ν•¨μˆ˜ μ‘°ν•©μš© λ©”μ„œλ“œ
Runnable μΈμžμ™€ λ°˜ν™˜κ°’μ΄ λͺ¨λ‘ μ—†μŒ. 단지 μ‹€ν–‰λ§Œ κ°€λŠ₯  
Function<T,R> 인자1개, λ°˜ν™˜1개 R apply(T t) andThen, Compose
BiFunction<T,U,R> 인자2개, λ°˜ν™˜1개 R apply(T t, U u)  
Consumer<T> 인자만 있음. void accept(T t) andThen
Supplier<T> λ°˜ν™˜κ°’λ§Œ 있음. T get()  
Predicate<T> λ°˜ν™˜κ°’λ§Œ 있음. boolean test(T t) And, Or, Negate
UnaryOperator<T> Function<T, T> 와 동일, μΈμžμ™€ 같은 μ œλ„€λ¦­ νƒ€μž…μ„ λ°˜ν™˜ν•¨  
BinaryOperator<T> BiFunction<T, T, T> 와 동일, μž…λ ₯κ°’ λ‘κ°œλ₯Ό λ°›μ•„ λ™μΌν•œ νƒ€μž…μ„ 리턴함.  
Comparator<T> BiFunction<T,T,Integer> 와 동일, κ°μ²΄κ°„μ˜ κ°’ λΉ„κ΅ν•˜λŠ”λ° μ‚¬μš©λ¨ (compare)  
기타 μƒλž΅ BiCosumer<T,U> BiPredicate<T,U>, ObjIntConsumer, LongSupplier λ“±.  

 

 


Function - R apply(T t)

import java.util.function.DoubleFunction;
import java.util.function.Function;

public class Main {
    public static void main(String[] args) {
        // μ΄λ ‡κ²Œ ν•¨μˆ˜λ₯Ό μ •μ˜ν•˜κ³  apply λ₯Ό μ΄μš©ν•˜μ—¬ ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€.
        Function<String, Integer> toStr = str -> Integer.parseInt(str);
        Integer result = toStr.apply("10");

        // μž…λ ₯값이 객체가 μ•„λ‹ˆλΌλ©΄ DoubleFunction, IntFunction 등을 μ‚¬μš©ν•΄λ„ λ©λ‹ˆλ‹€.
        DoubleFunction<Integer> func = a -> (int) (a * 10);
        System.out.println(func.apply(3.2)); // 32

        // μ΄λŠ” μœ„μ— μ½”λ“œμ™€ κ°™μŠ΅λ‹ˆλ‹€.
        Function<Integer,Integer> multiply10 = a -> (int) (a * 10);

        // μ΄λŸ°μ‹μœΌλ‘œ ν•¨μˆ˜λ₯Ό ν•©μ„±ν•΄μ„œ μ‚¬μš© ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.
        Function<String,Integer> toStringAndMultiply10 = multiply10.compose(toStr);
        System.out.println(toStringAndMultiply10.apply("10")); // 100
    }
}

 

BiFucntion - R apply(T t, U u)

import java.util.function.BiFunction;
  
public class Main {
    public static void main(String args[])
    {
        // add ν•¨μˆ˜λŠ” 인자 2개λ₯Ό λ°›μ•„ 더해 λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜μž…λ‹ˆλ‹€.
        BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
  
        // Fucntion μΈν„°νŽ˜μ΄μŠ€μ— κ΅¬ν˜„λœ apply λ©”μ„œλ“œλ₯Ό μ΄μš©ν•©λ‹ˆλ‹€.
        System.out.println("Sum = " + add.apply(2, 3));
  
        // multiply ν•¨μˆ˜λŠ” 두 인자λ₯Ό λ°›μ•„ κ³±ν•΄ λ°˜ν™˜ν•©λ‹ˆλ‹€.
        BiFunction<Integer, Integer, Integer> multiply = (a, b) -> a * b;
  
        // λ§ˆμ°¬κ°€μ§€λ‘œ applyλ₯Ό μ΄μš©ν•΄ ν•΄λ‹Ή ν•¨μˆ˜λ₯Ό μ‚¬μš© ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
        System.out.println("Product = " + multiply.apply(2, 3));
    }
}

 

 

Consumer<T> - void accept(T t) 

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;
  
public class Main {
    public static void main(String args[])
    {
        // display ν•¨μˆ˜λŠ” 숫자λ₯Ό 좜λ ₯ν•˜λŠ” ν•¨μˆ˜μž…λ‹ˆλ‹€.
        Consumer<Integer> display = a -> System.out.println(a);
  
        // Consumer μΈν„°νŽ˜μ΄μŠ€μ— λ‚΄μž₯된 accept을 μ‚¬μš©ν•©λ‹ˆλ‹€.
        display.accept(10);
  
        // modify ν•¨μˆ˜λŠ” Int 리슀트 λ‚΄μ˜ λͺ¨λ“  μš”μ†Œλ₯Ό 2배둜 κ³±ν•©λ‹ˆλ‹€.
        Consumer<List<Integer> > modify = list ->
        {
            for (int i = 0; i < list.size(); i++)
                list.set(i, 2 * list.get(i));
        };
  
        // dispList ν•¨μˆ˜λŠ” 리슀트 μ•ˆμ— μžˆλŠ” μˆ«μžλ“€μ„ 좜λ ₯ν•©λ‹ˆλ‹€.
        Consumer<List<Integer> >
            dispList = list -> list.stream().forEach(a -> System.out.print(a + " "));
  
        List<Integer> list = new ArrayList<Integer>();
        list.add(2);
        list.add(1);
        list.add(3);
  
        // μ΄λŸ°μ‹μœΌλ‘œ μ‚¬μš© ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
        modify.accept(list);
        dispList.accept(list);
    }
}

Supplier<T> - T get()

import java.util.function.Supplier;
  
public class Main {
    public static void main(String args[])
    {
  
        // randomValue ν•¨μˆ˜λŠ” λžœλ€ν•œ 값을 λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜μ΄λ‹€. μž…λ ₯은 μ—†λ‹€.
        Supplier<Double> randomValue = () -> Math.random();
  
        // Supplier μΈν„°νŽ˜μ΄μŠ€μ˜ get을 μ΄μš©ν•΄ 값을 μ–»μ–΄μ˜¨λ‹€.
        System.out.println(randomValue.get());
    }
}

 

Predicate<T> - boolean test(T t)

boolean 값을 기본으둜 μ‚¬μš©ν•˜λŠ” 만큼, .and(~) .or(~) .negate(~) 같은 λ©”μ„œλ“œκ°€ μ‘΄μž¬ν•œλ‹€.

import java.util.function.Predicate;

public class PredicateInterfaceExample1 {
    public static void main(String[] args)
    {
        // lesserthan ν•¨μˆ˜λŠ” iκ°€ 18보닀 μž‘μ€μ§€ κ²€μ‚¬ν•˜λŠ” ν•¨μˆ˜μ΄λ‹€.
        Predicate<Integer> lesserthan = i -> (i < 18); 
  
        // Predicate μΈν„°νŽ˜μ΄μŠ€μ˜ test λ©”μ„œλ“œλ₯Ό μ΄μš©ν•˜μ—¬ μ‚¬μš©ν•œλ‹€.
        System.out.println(lesserthan.test(10)); // true
    }
}

 

UnaryOperator<T>

- Function<T, R> μ‘μš©, 단일값을 μ‚¬μš©ν•˜λŠ” μ—°μ‚°μž ν•¨μˆ˜λ₯Ό κ΅¬ν˜„ν•  λ•Œ μ‚¬μš©ν•œλ‹€.

import java.util.function.Function;
import java.util.function.UnaryOperator;
  
public class GFG {
    public static void main(String args[])
    {
        UnaryOperator<Integer> xor = a -> a ^ 1;
        UnaryOperator<Integer> and = a -> a & 1;
        
        // composeλ₯Ό μ΄μš©ν•˜μ—¬ 2개의 연산을 ν•˜λ‚˜λ‘œ ν•©μΉœλ‹€.
        Function<Integer, Integer> compose = xor.compose(and);
        System.out.println(compose.apply(231));
    }
}

 

BinaryOperator<T>

- BiFunction<T, U, R> μ‘μš©. compare, max 같은 κΈ°λŠ₯을 ν•˜λŠ” ν•¨μˆ˜λ₯Ό κ΅¬ν˜„ν•  λ•Œ μ‚¬μš©ν•œλ‹€.

import java.util.function.BinaryOperator;
  
public class GFG {
    public static void main(String args[])
    {
    	// μ΄λŸ°μ‹μœΌλ‘œ μ‚¬μš©λœλ‹€λŠ”κ±° μ •λ„λ§Œ μ•Œκ³ μžˆμž.
        BinaryOperator<Integer>
            op = BinaryOperator
                     .maxBy(
                         (a, b) -> (a > b) ? 1 : ((a == b) ? 0 : -1));
  
        System.out.println(op.apply(98, 11));
    }
}

# effective final , μžλ°”μ˜ λ³€μˆ˜ 캑처 (Variable Capture)

λ‹€μŒκ³Ό 같이 Local 클래슀, 읡λͺ…ν΄λž˜μŠ€, λžŒλ‹€κ°€ μžˆλ‹€κ³  κ°€μ •ν•΄λ³΄μž.

import java.util.function.Consumer;
import java.util.function.IntConsumer;

public class Main {
    public static void main(String[] args) {
        int baseNumber = 10;
    
        // λ‚΄λΆ€ (Local) 클래슀
        class LocalClass {
            void print(int i) {
                System.out.println(i + baseNumber);
            }
        }

        // 읡λͺ… 클래슀
        Consumer<Integer> print = new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                System.out.println(integer + baseNumber);
            }
        };

        // λžŒλ‹€ ν‘œν˜„μ‹
        IntConsumer printInt = i -> System.out.println(i + baseNumber);
        printInt.accept(10);
    }
}

각각의 ν•¨μˆ˜λ“€μ€ 클래슀 μ•ˆμ˜ λ³€μˆ˜μΈ baseNumberλ₯Ό μ°Έμ‘°ν•˜κ³  μžˆλ‹€.

λ‚΄λΆ€ ν΄λž˜μŠ€λ‚˜ 읡λͺ… 클래슀의 경우, μŠ€μ½”ν”„{~} κ°€ 달라 λ‚΄λΆ€μ—μ„œ μ‚¬μš©ν•˜κ³ μžˆλŠ” baseNumberλΌλŠ” λ³€μˆ˜κ°€ μ‚¬μš©λ˜μ—ˆλŠ”μ§€ μ•ŒκΈ° μ–΄λ ΅λ‹€. 이λ₯Ό νŒŒλΌλ©”νƒ€κ°€ Shadowing λ˜μ—ˆλ‹€κ³  ν‘œν˜„ν•œλ‹€.

 

λ‚΄λΆ€ν΄λž˜μŠ€μ—μ„œ μ™ΈλΆ€μ˜ μ§€μ—­λ³€μˆ˜λ₯Ό μ‚¬μš©ν•˜κ²Œλ˜λ©΄

 

baseNumber κ°€ final ν‚€μ›Œλ“œλ‘œ μƒμˆ˜ν™” λ˜μ§€ μ•Šμ•˜λ”λΌλ„ λžŒλ‹€ ν‘œν˜„μ‹μ€ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©, 즉 μˆœμˆ˜ν•¨μˆ˜λ₯Ό 보μž₯ν•˜κΈ°μ— μ»΄νŒŒμΌμ‹œ μžλ™μœΌλ‘œ baseNumberλŠ” μƒμˆ˜ν™” λœλ‹€. 이λ₯Ό λ³€μˆ˜ 캑쳐(Variable Capture)라고 λ§ν•˜κ³  baseNumberλŠ” effective final 인 λ³€μˆ˜λΌκ³  λΆ€λ₯Έλ‹€.

 

λ³€μˆ˜ μΊ‘μ³λŠ” 말 κ·ΈλŒ€λ‘œ μ§€μ—­λ³€μˆ˜λ₯Ό λ³΅μ‚¬ν•΄μ„œ λ‹€λ₯Έ μ“°λ ˆλ“œλ‘œ κ°€μ Έμ˜¨λ‹€κ³  μ΄ν•΄ν•˜λ©΄ λœλ‹€. μ§€μ—­λ³€μˆ˜λŠ” JVMμ—μ„œ μ“°λ ˆλ“œλ§ˆλ‹€ λ³„λ„μ˜ μŠ€νƒμ˜μ—­μ— μ €μž₯λ˜λ―€λ‘œ, λ‹€λ₯Έ μŠ€μ½”ν”„ (=λ‹€λ₯Έ μ“°λ ˆλ“œ)κ°„μ˜ κ³΅μœ κ°€ μ–΄λ ΅λ‹€. λ‹€λ₯Έ μ“°λ ˆλ“œ μ˜μ—­μ—μ„œ 지역 λ³€μˆ˜λ₯Ό 가져와 μ‚¬μš©ν•˜κΈ° μœ„ν•΄μ„œλŠ” μ• μ΄ˆμ— μ „μ—­μœΌλ‘œ μ„ μ–Έν•˜κ±°λ‚˜ 지역 λ³€μˆ˜ 자체λ₯Ό λ³΅μ‚¬ν•΄μ„œ μ“°λ ˆλ“œλ‘œ κ°€μ Έμ˜€λŠ” 방법이 μžˆλ‹€. λ‹€λ§Œ 값을 볡사해왔을 경우 각각의 λ‹€λ₯Έ μ“°λ ˆλ“œμ—μ„œ 같은 λ³€μˆ˜μ˜ 값이 같을거라고 보μž₯ν•  수 μ—†λ‹€.

 

λžŒλ‹€λ₯Ό μ‚¬μš©ν•˜λŠ” ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ€ 기본적으둜 독립적인 μ“°λ ˆλ“œλ₯Ό μ‚¬μš©ν•  수 있게 μ„€κ³„λ˜μ–΄ μžˆκΈ°μ— μœ„μ˜ μ˜ˆμ œμ™€ 같이 μ§€μ—­λ³€μˆ˜λ₯Ό μ‚¬μš©ν•  λ•Œμ—λŠ” ν•΄λ‹Ή μ“°λ ˆλ“œμ˜ λ©”λͺ¨λ¦¬λ₯Ό μ°Έμ‘°ν•˜λŠ” 것이 μ•„λ‹ˆλΌ λ³€μˆ˜λ₯Ό 볡사 (=캑쳐)ν•˜μ—¬ λžŒλ‹€μ˜ μ“°λ ˆλ“œλ‘œ κ°€μ Έμ˜¨λ‹€. 이 λ•Œ λ³΅μ‚¬ν•œ 값이 달라지면 Side-effectκ°€ 생길 수 μžˆμœΌλ―€λ‘œ final ν‚€μ›Œλ“œλ₯Ό 톡해 μƒμˆ˜ν™” μ‹œν‚€λŠ” 것이닀.

Java 1.8이후 λͺ…μ‹œμ μœΌλ‘œ final을 μ„ μ–Έν•˜μ§€ μ•Šλ”λΌλ„ λžŒλ‹€μ—μ„œ μ‚¬μš©ν•˜λŠ” μ§€μ—­λ³€μˆ˜λŠ” μžλ™μœΌλ‘œ μƒμˆ˜ν™” (effective final)λœλ‹€.

 

μ‹€μ œλ‘œ λžŒλ‹€ ν‘œν˜„μ‹μ—μ„œ μ‚¬μš©ν•˜λŠ” baseNumber의 값을 λ³€κ²½ν•˜κ²Œλ˜λ©΄ μƒμˆ˜μ˜ 값을 λ³€κ²½ν–ˆλ‹€κ³  컴파일 였λ₯˜κ°€ 뜨게 λœλ‹€.

// baseNumber++; 같은 μ½”λ“œλ‘œ 값을 λ³€κ²½ν•˜λ©΄ 였λ₯˜κ°€ 뜨게 λœλ‹€. μƒμˆ˜λ₯Ό λ³€κ²½ν–ˆκΈ° λ•Œλ¬Έ.

C:\javaTest\src\com\company\Main.java:13:40
java: local variables referenced from an inner class must be final or effectively final

'🌱Backend > Java' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

#7 Exception (μ˜ˆμ™Έμ²˜λ¦¬)  (0) 2021.07.07
#6. Java - 2 클래슀 (μž‘μ„±μ˜ˆμ •)  (0) 2021.07.07
#5. μžλ°”μ˜ Interface  (2) 2021.07.01
#3. Java - 1 κΈ°μ΄ˆλ¬Έλ²•  (0) 2021.07.01
# 2. Java Naming Conventions  (2) 2021.06.30

λΈ”λ‘œκ·Έμ˜ 정보

JiwonDev

JiwonDev

ν™œλ™ν•˜κΈ°