source

Java 8: Java.util.function의 TriFunction(및 kin)은 어디에 있습니까?아니면 대체방법이 뭐죠?

factcode 2023. 1. 9. 21:12
반응형

Java 8: Java.util.function의 TriFunction(및 kin)은 어디에 있습니까?아니면 대체방법이 뭐죠?

java.util.function이 보입니다.BiFunction을 통해 다음을 수행할 수 있습니다.

BiFunction<Integer, Integer, Integer> f = (x, y) -> { return 0; };

그것만으로는 불충분하고 TriFunction이 필요한 경우에는 어떻게 해야 합니까?그건 존재하지 않아!

TriFunction<Integer, Integer, Integer, Integer> f = (x, y, z) -> { return 0; };

저만의 TriFunction을 정의할 수 있다는 것을 덧붙여야 할 것 같습니다.표준 라이브러리에 TriFunction을 포함하지 않는 이유를 이해하려고 합니다.

TriFunction이 필요한 경우 다음 작업을 수행합니다.

@FunctionalInterface
interface TriFunction<A,B,C,R> {

    R apply(A a, B b, C c);

    default <V> TriFunction<A, B, C, V> andThen(
                                Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (A a, B b, C c) -> after.apply(apply(a, b, c));
    }
}

다음 작은 프로그램은 어떻게 사용할 수 있는지 보여줍니다.결과 유형은 마지막 범용 유형 매개 변수로 지정된다는 점에 유의하십시오.

  public class Main {

    public static void main(String[] args) {
        BiFunction<Integer, Long, String> bi = (x,y) -> ""+x+","+y;
        TriFunction<Boolean, Integer, Long, String> tri = (x,y,z) -> ""+x+","+y+","+z;


        System.out.println(bi.apply(1, 2L)); //1,2
        System.out.println(tri.apply(false, 1, 2L)); //false,1,2

        tri = tri.andThen(s -> "["+s+"]");
        System.out.println(tri.apply(true,2,3L)); //[true,2,3]
    }
  }

되었는가?java.util.* ★★★★★★★★★★★★★★★★★」java.lang.*을 필요로 하지 .22개의 인수를 넘어서는 일은 없습니다.-) 즉, 컬렉션을 스트리밍할 수 있는 모든 새로운 코드는 메서드 파라미터로 TriFunction을 필요로 하지 않습니다.그래서 그것은 포함되지 않았다.

갱신하다

완전성을 위해 (커링과 관련된) 다른 답변에서 파괴적인 함수에 대한 설명을 따르기 위해 추가 인터페이스 없이 TriFunction을 에뮬레이트하는 방법을 다음에 나타냅니다.

Function<Integer, Function<Integer, UnaryOperator<Integer>>> tri1 = a -> b -> c -> a + b + c;
System.out.println(tri1.apply(1).apply(2).apply(3)); //prints 6

물론 다음과 같은 다른 방법으로 기능을 결합할 수 있습니다.

BiFunction<Integer, Integer, UnaryOperator<Integer>> tri2 = (a, b) -> c -> a + b + c;
System.out.println(tri2.apply(1, 2).apply(3)); //prints 6
//partial function can be, of course, extracted this way
UnaryOperator partial = tri2.apply(1,2); //this is partial, eq to c -> 1 + 2 + c;
System.out.println(partial.apply(4)); //prints 7
System.out.println(partial.apply(5)); //prints 8

커링은 람다 이외의 기능적 프로그래밍을 지원하는 모든 언어에서 자연스러운 것이지만, Java는 이러한 방식으로 구축되어 있지 않으며, 달성 가능하기는 하지만 코드를 유지하기가 어렵고 때로는 읽기도 어렵습니다.그러나, 이것은 연습으로서 매우 도움이 되고, 때때로 부분 함수가 코드 내에서 올바른 위치를 차지하기도 합니다.

제가 알기로는 파괴적인 기능과 건설적인 기능 두 가지밖에 없어요.

이름에서 알 수 있듯이 건설적인 기능은 무언가를 구성하지만 파괴적인 기능은 무언가를 파괴하지만 지금 여러분이 생각하는 방식으로는 아닙니다.

예를 들어 함수는

Function<Integer,Integer> f = (x,y) -> x + y  

건설적인 것입니다.무언가를 만들어야 하기 때문에.이 예에서는 태플(x,y)을 작성했습니다.구성 함수는 무한 인수를 처리할 수 없다는 문제가 있습니다.하지만 가장 나쁜 것은 논쟁을 그냥 미결로 둘 수는 없다는 것이다."x:= 1"이라고만 말하고 원하는 y마다 시도해 볼 수는 없습니다.당신은 모든 태플링에 매번 건설해야 한다.x := 1에 대해 y := 1, y := 2, y := 3 써야 돼요.f(1,1) , f(1,2) , f(1,3)

Java 8에서는 구성 함수는 구성 람다 함수를 사용하는 것이 별로 장점이 없기 때문에 메서드 참조를 사용하여 처리해야 합니다(대부분).그것들은 약간 정적인 방법과 비슷합니다.사용할 수 있지만 실제 상태는 없습니다.

다른 하나는 파괴적인 것입니다.그것은 무언가를 가져다가 필요에 따라서 분해합니다.를 들어, 파괴 함수는

Function<Integer, Function<Integer, Integer>> g = x -> (y -> x + y) 

does does does does does does does does does does function does function function function does does does does 와 같은 기능을 합니다.f설적적건파괴함수의 장점은 무한 인수를 처리할 수 있다는 것입니다.이는 스트림에 특히 편리하며 인수를 열어둘 수 있습니다. 다시 한 번 더 , 만약 ''가 된다면 어떤 요?x := 1 ★★★★★★★★★★★★★★★★★」y := 1 , y := 2 , y := 3 하면 h = g(1) ★★★★★★★★★★★★★★★★★」h(1) is is is for for의 y := 1,h(2)★★★★★★에y := 2 ★★★★★★★★★★★★★★★★★」h(3)★★★★★★에y := 3

그럼 여기 고정된 상태가 있군요!그것은 매우 역동적이고 우리가 람다에서 원하는 대부분의 시간입니다.

Factory와 같은 패턴은 자신에게 맞는 기능을 넣는 것만으로 훨씬 쉬워집니다.

파괴적인 것들은 서로 쉽게 결합된다.타입이 맞으면 그냥 원하는 대로 구성해도 돼요.이를 통해 (불변의 값으로) 테스트를 훨씬 쉽게 하는 형태론을 쉽게 정의할 수 있습니다!

건설적인 것도 할 수 있지만 파괴적인 구성은 더 멋지고 리스트나 장식가처럼 보이고 건설적인 것은 나무처럼 보입니다.건설적인 기능을 가진 역추적 같은 것은 좋지 않습니다.파괴 기능(동적 프로그래밍)의 부분 함수를 저장하고 "백트랙"에서는 이전 파괴 기능만 사용할 수 있습니다.그러면 코드가 훨씬 작고 읽기 쉬워집니다.건설적인 함수를 사용하면 모든 인수를 기억할 수 있습니다.이것은 많은 수가 될 수 있습니다.

왜 '우리'가 요?BiFunction 더 일 것이다TriFunction

우선, 값이 몇 개(3개 미만)밖에 없고 결과만 필요한 경우가 많기 때문에 일반적인 파괴 함수는 전혀 필요하지 않고 건설적인 것으로 충분합니다.하지만 딱히 .BiFunction조금도.그건 제거되어야 한다는 뜻이 아니야!나는 죽을 때까지 모나드를 위해 싸운다!

따라서 논리 컨테이너 클래스로 결합할 수 없는 인수가 많고 함수가 건설적일 필요가 있는 경우 메서드 참조를 사용합니다.그렇지 않으면 새로 얻은 파괴 기능을 사용하려고 하면 코드 라인이 훨씬 적은 상태에서 많은 작업을 수행할 수 있습니다.

또는 다음과 같은 종속성을 추가합니다.

<dependency>
    <groupId>io.vavr</groupId>
    <artifactId>vavr</artifactId>
    <version>0.9.0</version>
</dependency>

Vavr 함수는 다음과 같이 최대 8개의 인수를 사용할 수 있습니다.

3개의 인수:

Function3<Integer, Integer, Integer, Integer> f = 
      (a, b, c) -> a + b + c;

5개의 인수:

Function5<Integer, Integer, Integer, Integer, Integer, Integer> f = 
      (a, b, c, d, e) -> a + b + c + d + e;

나는 거의 같은 질문과 부분적인 답변을 가지고 있다.건설적/파괴적 답변이 언어 디자이너가 염두에 둔 것인지 확실하지 않습니다.N까지 3개 이상이면 유효한 사용 사례가 있다고 생각합니다.

출신입니다.NET 및 의NET Void 기능을 위한 Func와 Action이 있습니다.술어 및 기타 특수한 경우도 존재합니다.참조: https://msdn.microsoft.com/en-us/library/bb534960(v=vs.110).aspx

언어디자이너들이 Function, Biffunction을 선택하고 DecaExiFunction까지 계속하지 않은 이유가 무엇인지 궁금합니다.

두 번째 부분에 대한 답은 유형 삭제입니다.컴파일 후 Func와 Func의 차이는 없습니다.따라서 다음 항목은 컴파일되지 않습니다.

package eu.hanskruse.trackhacks.joepie;

public class Functions{

    @FunctionalInterface
    public interface Func<T1,T2,T3,R>{
        public R apply(T1 t1,T2 t2,T3 t3);
    }

    @FunctionalInterface
    public interface Func<T1,T2,T3,T4,R>{
        public R apply(T1 t1,T2 t2,T3 t3, T4 t4);
    }
}

또 다른 사소한 문제를 회피하기 위해 내부 기능이 사용되었습니다.이클립스는 같은 디렉토리에 함수라는 이름의 파일에 두 클래스를 둘 것을 고집했다.이것이 요즘 컴파일러의 문제인지 아닌지 확실하지 않습니다.하지만 나는 이클립스의 오류를 되돌릴 수 없다.

펑크는 java 함수 유형과 이름이 충돌하지 않도록 하기 위해 사용되었습니다.

따라서 Func를 3에서 16까지 인수로 추가할 경우 두 가지 작업을 수행할 수 있습니다.

  • TriFunc, TesseraFunc, PendeFunc 등을 만듭니다.DecaExiFunc 등
    • (그리스어로 할까요, 아니면 라틴어로 할까요?)
  • 패키지 이름 또는 클래스를 사용하여 이름을 다르게 만듭니다.

두 번째 방법의 예:

 package eu.hanskruse.trackhacks.joepie.functions.tri;

        @FunctionalInterface
        public interface Func<T1,T2,T3,R>{
            public R apply(T1 t1,T2 t2,T3 t3);
        }

그리고.

package eu.trackhacks.joepie.functions.tessera;

    @FunctionalInterface
    public interface Func<T1,T2,T3,T4,R>{
        public R apply(T1 t1,T2 t2,T3 t3, T4 t4);
    }

어떤 접근법이 가장 좋을까요?

위의 예에서는 And Then() 메서드와 compose() 메서드의 실장은 포함하지 않았습니다.이들을 추가할 경우 각각 16개의 오버로드를 추가해야 합니다.TriFunc에는 16개의 인수를 가진andthen()이 필요합니다.순환 종속성으로 인해 컴파일 오류가 발생합니다.또한 기능 및 BiFunction에 대한 과부하가 발생하지 않습니다.따라서 Func를 1개의 인수로 정의하고 Func를 2개의 인수로 정의해야 합니다..NET에서는 Java에는 없는 확장 메서드를 사용하여 순환 종속성을 회피할 수 있습니다.

3개의 파라미터를 사용하여 독자적인 기능을 만들 수도 있습니다.

@FunctionalInterface
public interface MiddleInterface<F,T,V>{
    boolean isBetween(F from, T to, V middleValue);
}

MiddleInterface<Integer, Integer, Integer> middleInterface = 
(x,y,z) -> x>=y && y<=z; // true

BiFunction의 소스 코드를 찾았습니다.

https://github.com/JetBrains/jdk8u_jdk/blob/master/src/share/classes/java/util/function/BiFunction.java

TriFunction을 만들기 위해 수정했습니다.BiFunction과 마찬가지로 and Then()을 사용하고 compose()를 사용하지 않기 때문에 compose()를 필요로 하는 어플리케이션에는 적합하지 않을 수 있습니다.보통 물건이라면 괜찮을 겁니다.And Then() 및 compose()에 대한 좋은 기사는 다음 URL에서 찾을 수 있습니다.

http://www.deadcoderising.com/2015-09-07-java-8-functional-composition-using-compose-and-andthen/

import java.util.Objects;
import java.util.function.Function;

/**
 * Represents a function that accepts two arguments and produces a result.
 * This is the three-arity specialization of {@link Function}.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #apply(Object, Object)}.
 *
 * @param <S> the type of the first argument to the function
 * @param <T> the type of the second argument to the function
 * @param <U> the type of the third argument to the function
 * @param <R> the type of the result of the function
 *
 * @see Function
 * @since 1.8
 */
@FunctionalInterface
public interface TriFunction<S, T, U, R> {

    /**
     * Applies this function to the given arguments.
     *
     * @param s the first function argument
     * @param t the second function argument
     * @param u the third function argument
     * @return the function result
     */
    R apply(S s, T t, U u);

    /**
     * Returns a composed function that first applies this function to
     * its input, and then applies the {@code after} function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     * @param <V> the type of output of the {@code after} function, and of the
     *           composed function
     * @param after the function to apply after this function is applied
     * @return a composed function that first applies this function and then
     * applies the {@code after} function
     * @throws NullPointerException if after is null
     */
    default <V> TriFunction<S, T, U, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (S s, T t, U u) -> after.apply(apply(s, t, u));
    }
}

한 '심플한'Function<T, R> 수 .TriFunction

다음은 간단한 예입니다.

       final Function<Integer, Function<Integer, Function<Integer, Double>>> function = num1 -> {
            System.out.println("Taking first parameter");
            return num2 -> {
                System.out.println("Taking second parameter");
                return num3 -> {
                    System.out.println("Taking third parameter");
                    return (double)(num1 + num2 + num3);
                };
            };
        };

        final Double result = function.apply(2).apply(3).apply(4);

        System.out.println("Result -> " + result);

출력 -

Taking first parameter
Taking second parameter
Taking third parameter
Result -> 9.0

이 로직을 확장하여 함수가 원하는 수의 파라미터를 받아들이도록 할 수 있습니다.

항상 트라이 펑션에 들를 수는 없습니다.경우에 따라 n개의 파라미터를 함수에 전달해야 할 수 있습니다.그 후 지원팀은 코드를 수정하기 위한 QuadFunction을 작성해야 합니다.장기적인 해결책은 추가 매개 변수를 사용하여 개체를 만든 다음 이미 만들어진 기능 또는 BiFunction을 사용하는 것입니다.

설명이 좀 복잡하긴 하지만 선택된 답변이 가장 도움이 됩니다.

단순화하기 위해 두 개의 문자열을 추가하는 함수를 사용한다고 가정해 보겠습니다.

방법

String add(String s, String t) {
    return s + t;
}

같은 동작으로 다음과 같은 기능이 있습니다.

Function<String,Function<String,String>> add = s -> t -> s + t;

그리고 그걸 뭐라고 부르면:

var result = add.apply("hello").apply(" world");

이것이 관용 자바인지 아닌지는 다른 주제이다.

Consumer3를 사용할 준비가 되었습니다.컨슈머 8, 기능 3..Function 8, 술어3..Spring Framework에 번들된 Reactor Addons 라이브러리의 패키지에 있는 술어 8.

언급URL : https://stackoverflow.com/questions/18400210/java-8-where-is-trifunction-and-kin-in-java-util-function-or-what-is-the-alt

반응형