#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