JDK8의 새로운 특성에 대한 Lambda 표현식 분석
하나.행위 매개 변수화
행위 매개 변수화는 간단하게 말하면 함수의 주체는 템플릿류의 유니버설 코드만 포함하고 업무 장면에 따라 변화하는 논리는 매개 변수의 형식으로 함수에 전달된다. 행위 매개 변수화를 사용하면 프로그램을 더욱 유니버설하게 하고 빈번한 변경의 수요에 대응할 수 있다.
하나의 업무 장면을 고려하여 우리가 프로그램을 통해 애플을 선별해야 한다고 가정하면 우리는 먼저 애플의 실체를 정의한다.
public class Apple {
/** */
private long id;
/** */
private Color color;
/** */
private float weight;
/** */
private String origin;
public Apple() {
}
public Apple(long id, Color color, float weight, String origin) {
this.id = id;
this.color = color;
this.weight = weight;
this.origin = origin;
}
// getter setter
}
사용자의 초기 수요는 단지 프로그램을 통해 녹색 애플을 선별하기를 바라는 것일 수도 있다. 그래서 우리는 프로그램을 통해 신속하게 실현할 수 있다.
public static List<Apple> filterGreenApples(List<Apple> apples) {
List<Apple> filterApples = new ArrayList<>();
for (final Apple apple : apples) {
if (Color.GREEN.equals(apple.getColor())) {
filterApples.add(apple);
}
}
return filterApples;
}
이 코드는 매우 간단해서 말할 만한 것이 없다.그러나 사용자의 수요가 녹색으로 바뀌면 코드 수정도 간단해 보인다. 판단 조건의 녹색을 빨간색으로 바꾸는 것이 아니다.그러나 우리는 또 다른 문제를 고려해야 한다. 만약 변화 조건이 빈번하게 바뀐다면?만약에 색의 변화일 뿐이라면 우리는 사용자로 하여금 색의 판단 조건을 전달하게 하고 판단 방법의 매개 변수는'판단할 집합과 선별할 색'이다.그러나 사용자가 색깔만 판단하는 것이 아니라 무게, 크기, 크기를 판단하고 싶다면 어떡하지?너는 우리가 순서대로 다른 매개 변수를 추가하여 판단을 완성하면 된다고 생각하니?그런데 이렇게 매개 변수를 전달하는 방식이 정말 좋아요?만약 선별 조건이 갈수록 많아지고 조합 모델이 갈수록 복잡해진다면 우리는 모든 상황을 고려하고 모든 상황에 대해 상응하는 대응 전략을 가져야 하지 않겠는가?이때 우리는 행위를 매개 변수화하고 선별 조건을 추출하여 매개 변수로 전달할 수 있다. 이때 우리는 판단의 인터페이스를 봉인할 수 있다.
public interface AppleFilter {
/**
*
*
* @param apple
* @return
*/
boolean accept(Apple apple);
}
/**
*
*
* @param apples
* @param filter
* @return
*/
public static List<Apple> filterApplesByAppleFilter(List<Apple> apples, AppleFilter filter) {
List<Apple> filterApples = new ArrayList<>();
for (final Apple apple : apples) {
if (filter.accept(apple)) {
filterApples.add(apple);
}
}
return filterApples;
}
위의 행동을 추상화한 후에 우리는 구체적으로 호출된 곳에 선별 조건을 설정하고 조건을 매개 변수로 방법에 전달할 수 있다. 이때 익명 내부 클래스의 방법을 사용한다.
public static void main(String[] args) {
List<Apple> apples = new ArrayList<>();
//
List<Apple> filterApples = filterApplesByAppleFilter(apples, new AppleFilter() {
@Override
public boolean accept(Apple apple) {
// 100g
return Color.RED.equals(apple.getColor()) && apple.getWeight() > 100;
}
});
}
이런 디자인은 jdk 내부에서도 자주 사용된다. 예를 들어 Java.util.Comparator,java.util.concurrent.Callable 등은 이러한 인터페이스를 사용할 때 우리는 구체적으로 호출된 곳에서 익명 클래스를 사용하여 함수의 구체적인 실행 논리를 지정할 수 있다. 그러나 위의 코드 블록을 보면 매우 친절하지만 간결하지 않다. java8에서 우리는 lambda를 통해 간소화할 수 있다.
//
List<Apple> filterApples = filterApplesByAppleFilter(apples,
(Apple apple) -> Color.RED.equals(apple.getColor()) && apple.getWeight() >= 100);
//()->xxx () ,xxx
2.lambda 표현식 정의우리는 lambda표현식을 간결하고 전달할 수 있는 익명 함수로 정의할 수 있다. 우선 우리는 lambda표현식이 본질적으로 하나의 함수라는 것을 명확히 해야 한다. 비록 특정한 종류에 속하지 않지만 매개 변수 목록, 함수 주체, 반환 유형, 그리고 이상을 던질 수 있다.그 다음은 익명이고 lambda 표현식은 구체적인 함수 이름이 없다.lambda 표현식은 매개 변수처럼 전달되어 코드의 작성을 크게 간소화할 수 있다.형식 정의는 다음과 같습니다.
형식 1: 매개변수 목록 -> 표현식
형식2: 매개 변수 목록 -> {표현식 집합}
주의해야 할 것은 lambda 표현식은return 키워드를 포함하고 있기 때문에 하나의 표현식에서 우리는 return 키워드를 현저하게 쓸 필요가 없다. 그러나 표현식이 하나의 문장 집합일 때 return을 현저하게 추가하고 괄호 {}로 여러 개의 표현식을 둘러싸야 한다. 다음은 몇 가지 예를 본다.
// , return
(String s) -> s.length()
// 42
() -> 42
// ,
(int x, int y) -> {
int z = x * y;
return x + z;
}
셋.함수식 인터페이스에 의존하여 lambda 표현식을 사용하다lambda 표현식의 사용은 함수식 인터페이스를 빌려야 한다. 즉, 함수식 인터페이스가 나타나야만 우리는 이를 lambda 표현식으로 간소화할 수 있다.
사용자 정의 함수 인터페이스:
함수식 인터페이스는 하나의 추상적인 방법만 갖춘 인터페이스로 정의된다.java8의 인터페이스 정의에 대한 개선은 기본 방법을 도입하여 인터페이스에서 방법에 대한 기본적인 실현을 제공할 수 있도록 하는 것이다. 그러나 몇 개의 기본 방법이 존재하든 추상적인 방법이 하나만 있으면 함수식 인터페이스이다. 아래와 같다. (위의 AppleFilter 참조)
/**
*
*/
@FunctionalInterface
public interface AppleFilter {
/**
*
*
* @param apple
* @return
*/
boolean accept(Apple apple);
}
AppleFilter는 추상적인 방법인 accept(Apple apple)만 포함하고 정의에 따라 함수식 인터페이스로 간주할 수 있습니다. 정의할 때 우리는 이 인터페이스에 @FunctionalInterface 주석을 추가했습니다. 이 인터페이스는 함수식 인터페이스라고 표시하는 데 사용되지만, 이 인터페이스는 선택할 수 있습니다. 이 인터페이스를 추가한 후에 컴파일러는 이 인터페이스에 추상적인 방법만 허용할 수 있도록 제한합니다. 그렇지 않으면 오류가 발생합니다.그래서 함수식 인터페이스에 이 주석을 추가하는 것을 추천합니다.jdk 자체 함수식 인터페이스:
jdk는 lambda 표현식에 풍부한 함수식 인터페이스를 내장했다. 다음은 각각Predicate
Predicate:
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
}
Predicate의 기능은 위의 AppleFilter와 유사합니다. 우리가 외부에서 설정한 조건을 이용하여 전송된 매개 변수를 검사하고 검증 결과를 boolean으로 되돌려줍니다. 다음은 Predicate를 이용하여 List 집합된 요소를 필터합니다.
/**
*
* @param list
* @param predicate
* @param <T>
* @return
*/
public <T> List<T> filter(List<T> list, Predicate<T> predicate) {
List<T> newList = new ArrayList<T>();
for (final T t : list) {
if (predicate.test(t)) {
newList.add(t);
}
}
return newList;
}
사용:
demo.filter(list, (String str) -> null != str && !str.isEmpty());
Consumer
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
}
Consumer는 accept 추상적인 함수를 제공합니다. 이 함수는 파라미터를 수신하지만 값을 되돌려 주지 않습니다. 다음은 Consumer를 이용하여 집합을 반복합니다.
/**
* ,
*
* @param list
* @param consumer
* @param <T>
*/
public <T> void filter(List<T> list, Consumer<T> consumer) {
for (final T t : list) {
consumer.accept(t);
}
}
위의 함수식 인터페이스를 사용하여 문자열 집합을 반복하고 비어 있지 않은 문자열을 인쇄합니다.
demo.filter(list, (String str) -> {
if (StringUtils.isNotBlank(str)) {
System.out.println(str);
}
});
Function
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
}
Funcation 은 T타입의 데이터를 입력하고 R타입의 데이터를 되돌려줍니다. 다음은 Function 을 이용하여 집합을 변환합니다.
public <T, R> List<R> filter(List<T> list, Function<T, R> function) {
List<R> newList = new ArrayList<R>();
for (final T t : list) {
newList.add(function.apply(t));
}
return newList;
}
기타:
demo.filter(list, (String str) -> Integer.parseInt(str));
위의 함수식 인터페이스는 논리적 조작의 기본 실현도 제공합니다. 다음에 자바8 인터페이스의 기본 방법을 소개할 때 말씀해 주십시오.사용 과정에서 주의해야 할 몇 가지 사항:
유형 추정:
인코딩 과정에서 때때로 우리의 호출 코드가 어떤 함수식 인터페이스와 구체적으로 일치하는지 의심할 수 있다. 실제로 컴파일러는 매개 변수, 반환 유형, 이상 유형(존재할 경우) 등에 따라 정확한 판정을 한다.
특정 호출 시 매개변수 유형을 생략하여 코드를 단순화할 수 있습니다.
//
List<Apple> filterApples = filterApplesByAppleFilter(apples,
(Apple apple) -> Color.RED.equals(apple.getColor()) && apple.getWeight() >= 100);
// ,
List<Apple> filterApples = filterApplesByAppleFilter(apples,
apple -> Color.R
ED.equals(apple.getColor()) && apple.getWeight() >= 100);
국부 변수위의 모든 예에서 우리의lambda표현식은 그 주체 파라미터를 사용하고 우리는lambda에서 국부 변수를 사용할 수 있다. 다음과 같다.
int weight = 100;
List<Apple> filterApples = filterApplesByAppleFilter(apples,
apple -> Color.RED.equals(apple.getColor()) && apple.getWeight() >= weight);:
이 예에서 우리는 lambda에서 국부 변수weight를 사용했지만 lambda에서 국부 변수를 사용하려면 이 변수가final 또는 사실상의final로 명시되어야 한다. 이것은 국부 변수가 창고에 저장되어 있기 때문이다. lambda 표현식은 다른 라인에서 실행되고 이 라인 보기가 이 국부 변수에 접근할 때 이 변수가 변경되거나 회수될 가능성이 있기 때문이다.그래서final로 수식하면 라인 안전에 문제가 없습니다.사.메소드 참조
메서드를 사용하여 한 단계 더 가까운 단순화 코드를 참조할 수 있습니다. 때때로 이러한 단순화는 코드를 더욱 직관적으로 보일 수 있습니다. 예를 들어 다음과 같습니다.
/* ... apples */
// lambda
apples.sort((Apple a, Apple b) -> Float.compare(a.getWeight(), b.getWeight()));
//
apples.sort(Comparator.comparing(Apple::getWeight));
메서드 참조는 다음과 같습니다. 메서드 예속과 메서드 자체를 연결하면 다음과 같은 세 가지 유형으로 나뉩니다.정적 방법
(args) -> ClassName.staticMethod(args)
변환
ClassName::staticMethod
매개 변수의 실례 방법
(args) -> args.instanceMethod()
변환
ClassName::instanceMethod // ClassName args
외부 인스턴스 방법
(args) -> ext.instanceMethod(args)
변환
ext::instanceMethod(args)
참조:http://www.codeceo.com/article/lambda-of-java-8.html
위에서 말한 것은 편집자가 여러분께 소개한 JDK8의 새로운 특성의 Lambda 표현식입니다. 여러분께 도움이 되었으면 합니다. 만약에 궁금한 것이 있으면 저에게 메시지를 남겨 주십시오. 편집자는 제때에 여러분에게 회답할 것입니다.여기에서도 저희 사이트에 대한 지지에 감사드립니다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
jdk8의datetime 시간 함수 사용 예시JDK8이 발표되었습니다.datetime 시간 함수 사용 방법의 작은 예시를 썼습니다 실행 결과...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.