y = f(x) 형태의 함수로 구성된 프로그래밍 기법
Java 8에서 함수형 프로그래밍 방식인 람다식을 지원한다.
객체지향 프로그래밍보다는 함수형 프로그래밍에 가깝다고 할 수 있다.
람다식이란? 함수(메서드)를 간단한 ‘식(Expression)’으로 표현하는 방법
- 함수는 클래스에 독립적, 메소드는 클래스에 종속적
- 메서드의 이름과 반환타입을 제거하고 ‘->’를 블록{} 앞에 추가한다.
- 반환값이 있는 경우, 식이나 값만 적고 return문 생략 가능(끝에‘;’안 붙임)
- 매개변수의 타입이 추론 가능하면 생략가능(대부분의 경우 생략가능)
- 매개변수가 하나인 경우, 괄호() 생략가능(타입이 없을 때만)
- 블록 안의 문장이 하나뿐 일 때, 괄호{}생략가능(끝에 ‘;’ 안 붙임)
- 단, 하나뿐인 문장이 return문이면 괄호{} 생략불가
람다식 장점
1. 코드를 간결하게 만들 수 있다.
2. 코드가 간결하고 식에 개발자의 의도가 명확히 드러나므로 가독성이 향상된다.
3. 함수를 만드는 과정없이 한번에 처리할 수 있기에 코딩하는 시간이 줄어든다.
4. 병렬프로그래밍이 용이하다.
람다식 단점
1. 람다를 사용하면서 만드는 익명함수는 재사용이 불가능하다.
2. 디버깅이 다소 까다롭다.
3. 람다를 남발하면 코드가 지저분해질 수 있다.
4. 재귀로 만들경우에는 다소 부적합한면이 있다.
@FunctionalInterface
interface MyFunction {
// 함수형 인터페이스 : 단 하나의 추상 메소드만 선언된 인터페이스
int max(int a, int b); // public abstract 생략
}
public class LambdaEX1 {
public static void main(String[] args) {
// 람다식(익명 객체)을 다루기 위한 참조변수의 타입은 함수형 인터페이스로 한다.
MyFunction f = (a, b) -> a > b ? a : b;
int value = f.max(3,5);
System.out.println(value);
}
}
|
@FunctionalInterface
interface MyFunctionalInterface{
// 함수형 인터페이스 : 단 하나의 추상 메소드만 선언된 인터페이스
void method();
}
public class LambdaEX2 {
public static void main(String[] args) {
MyFunctionalInterface fi1 = new MyFunctionalInterface() {
@Override
public void method() {
String str = "직접 익명 객체 구현함";
System.out.println(str);
}
};
fi1.method();
MyFunctionalInterface fi2 = () -> {
String str = "람다식 익명 객체 구현함";
System.out.println(str);
};
fi2.method();
}
}
|
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@FunctionalInterface
interface MyFunctionIF {
// 함수형 인터페이스 : 단 하나의 추상 메소드만 선언된 인터페이스
int max(int a, int b); // public abstract 생략
}
public class LambdaEX1 {
public static void main(String[] args) {
// 람다식(익명 객체)을 다루기 위한 참조변수의 타입은 함수형 인터페이스로 한다.
MyFunctionIF f = (a, b) -> a > b ? a : b;
int value = f.max(3,5);
System.out.println(value);
int result = Integer.parseInt("123");
System.out.println(result);
System.out.println("===================================");
ArrayList<Integer> list = new ArrayList<>();
for(int i=0;i < 20;i++)
list.add(i);
System.out.println(list);
// list의 모든 요소를 출력
list.forEach(i->System.out.print(i + ", "));
System.out.println();
// list에서 2 또는 3의 배수를 제거한다.
list.removeIf(x -> x%2==0 || x%3==0);
System.out.println(list);
list.replaceAll(i->i*3); // list의 각 요소에 3을 곱한다.
System.out.println(list);
System.out.println("===================================");
Map<String, String> map = new HashMap<>();
map.put("1", "1");
map.put("2", "2");
map.put("3", "3");
map.put("4", "4");
// map의 모든 요소를 {k,v}의 형식으로 출력한다.
map.forEach((k,v)-> System.out.print("{"+k+","+v+"},"));
System.out.println();
}
}
|
메소드 참조
메소드 레퍼런스(Method Reference)는 Lambda 표현식을 더 간단하게 표현하는 방법이다.
메소드 레퍼런스는 ClassName::MethodName 형식으로 입력한다.
메소드를 호출하는 것이지만 괄호()는 써주지 않고 생략한다.
import java.util.Arrays;
import java.util.List;
import java.util.function.BinaryOperator;
import java.util.function.IntBinaryOperator;
class MathBox {
// 클래스::메소드 --> 정적(static) 메소드 참조
public static int staticPlus(int x, int y){
return x+y;
}
// 참조변수::메소드 --> 인스턴스 메소드 참조
public int sum(int x, int y){
return x+y;
}
// 정수 빼기
public int sub(int x, int y){
return x-y;
}
// 정수 나누기
public int division(int x, int y){
return x / y;
}
// 실수 나누기
public Float float_div(Float x, Float y){
return x / y;
}
}
public class Method_References {
public static void main(String[] args) {
List<String> strList = Arrays.asList("안녕", "하세요");
strList.stream().forEach(System.out::println);
// static 메소드 참조
IntBinaryOperator operator1;
// 메소드 참조해서 매개변수 리턴타입 알아내 람다식에서 불필요한 매개변수 제거 목적
operator1 = MathBox::staticPlus; // 메소드 참조
System.out.println(operator1.applyAsInt(5, 3));
operator1 = (x, y) -> MathBox.staticPlus(x, y);
System.out.println(operator1.applyAsInt(3, 5));
// instance 메소드 참조
MathBox calculator = new MathBox();
IntBinaryOperator operator2 = calculator::sum; // 메소드 참조
System.out.println("더하기 : " + operator2.applyAsInt(11, 32));
operator1 = (x, y) -> calculator.sum(x, y);
System.out.println(operator1.applyAsInt(11, 32));
operator2 = calculator::sub; // 메소드 참조
System.out.println("빼기 : " + operator2.applyAsInt(11, 30));
operator2 = calculator::division; // 메소드 참조
System.out.println("나누기 : " + operator2.applyAsInt(15, 4));
BinaryOperator<Integer> operator3 = (n1, n2) -> n1 + n2; // 타입 추론
Integer sum = operator3.apply(10, 100);
System.out.println(sum);
BinaryOperator<Float> operator4 = calculator::float_div;
System.out.println("나누기 : " + operator4.apply(15.0f, 4.0f));
BinaryOperator<Float> operator5 = (n1, n2) -> n1 / n2; // 타입 추론
Float div = operator5.apply(15.0f, 4.0f);
System.out.println(div);
}
}
|
자바에서 제공하는 함수형 인터페이스를 이용하면 인터페이스를 만들지 않고 간단하게 코드 구현 가능하다.
import java.util.function.Consumer;
interface Printable {
void doSomething(String text);
}
public class MethodReferencesEX2 {
public static class Printer {
static void printSomething(String text) {
System.out.println(text);
}
}
public static void main(String[] args) {
Printable printable = text -> Printer.printSomething(text);
printable.doSomething("do something");
Printable printable2 = Printer::printSomething;
printable2.doSomething("do something");
// Consumer<클래스>는 자바에서 제공하는 함수형 인터페이스
// String 1개를 인자로 받아 void를 리턴하는 메소드를 갖고 있는 인터페이스
Consumer<String> consumer = Printer::printSomething;
consumer.accept("do something"); // Printable 인터페이스를 만들 필요가 없다.
}
}
|
'안드로이드 > Java 문법' 카테고리의 다른 글
[Java] HashSet 예제 (0) | 2020.12.12 |
---|---|
Java 와 C/C++ 비교 (0) | 2020.11.08 |
[Java] 다형성 : 참조변수 형변환, 매개변수 다형성 (0) | 2020.07.08 |
[Java] 접근 제어자(access modifier) (0) | 2020.07.08 |
Java Thread synchronized (동기화) (0) | 2019.11.09 |