6

ストリーム内でオブジェクトを分割できるかどうか疑問に思っています。たとえば、次の場合Employee:

public class Employee {

    String name;
    int age;
    double salary;

    public Employee(String name, int age, double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    public String getName() { return name; }

    public int getAge() { return age; }

    public double getSalary() { return salary; }
}

ストリームで何らかの操作を実行したいと思います。簡単にするために、次のようにします (私のコード アーキテクチャでは、これを Employee クラス内に配置できないと仮定します。そうしないと、簡単すぎます)。

public void someOperationWithEmployee(String name, int age, double salary) {
    System.out.format("%s %d %.0f\n", name, age, salary);
}

次のようになります。

Stream.of(new Employee("Adam", 38, 3000), new Employee("John", 19, 2000))
        // some conversations go here ...
        .forEach(e -> someOperationWithEmployee(e.getName, e.getAge(), e.getSalary));

問題は、このようなストリーム内にコードを入れることは可能ですか?

Stream.of(new Employee("Adam", 38, 3000), new Employee("John", 19, 2000))
        // some conversations go here
        .forEach((a, b, c) -> someOperationWithEmployee(a, b, c));

私は何を達成しようとしていますか?.forEach(this::someOperationWithEmployee)- いくつかのオブジェクト フィールドをマッピングして、コードの可読性が少し向上するように処理できればと思います。


2015 年 5 月 14 日更新

Employeeこの場合、オブジェクトを渡すことが間違いなくsomeOperationWithEmployee最も美しい解決策ですが、実際にはこれを行うことができない場合があり、ラムダを使用した普遍的な解決策にする必要があります。

4

3 に答える 3

5

短い答えはノーです。これはできません。私が考えることができる最短の解決策は、次のように独自の機能インターフェイスを定義することです。

import java.util.function.Function;

@FunctionalInterface
public interface TriFunction<A,B,C,R> {
    R apply(A a, B b, C c);

    static <I,A,B,C,R> Function<I,R> convert(TriFunction<A,B,C,R> triFn, Function<I,A> aFn, 
                                             Function<I,B> bFn, Function<I,C> cFn) {
        return i -> triFn.apply(aFn.apply(i), bFn.apply(i), cFn.apply(i));
    }
}

そして、次のように使用します。

Stream.of(new Employee("Adam", 38, 3000), new Employee("John", 19, 2000))
    // some conversations go here
    .forEach(TriFunction.convert((a, b, c) -> someOperationWithEmployee(a, b, c), 
         Employee::getName, Employee::getAge, Employee::getSalary));

それは美しいとは言えませんが。

オブジェクトを引数としてsomeOperationWithEmployee取った方がずっと良いと思います。Employee

更新: 値のペアについては、次のように無料のStreamExライブラリを使用できます。

StreamEx.of(new Employee("Adam", 38, 3000), new Employee("John", 19, 2000))
    // some conversations go here
    .mapToEntry(Employee::getName, Employee::getAge)
    .forKeyValue((a, b) -> someOperationWithEmployee(a, b));

ただし、ペアのみに限定されているため、この方法で 3 つ以上の値を処理することはできません (そのような関数を追加するつもりはありません)。

タプルに集中していて、すでにFunction3. ただし、問題に使用する簡単な方法もないようです。

于 2015-05-14T08:41:29.257 に答える
0

ここでは、反射なしのuser270349の回答を独自の方法で再設計します。静的インポートでは、次のように使用できます。

Stream.of(new Employee("Adam", 38, 3000), new Employee("John", 19, 2000))
        .map(e -> retrieve(e::getName, e::getAge, e::getSalary))
        .forEach(c -> c.call(this::printNameAgeSalary));

またはそのように:

Stream.of(new Employee("Adam", 38, 3000), new Employee("John", 19, 2000))
        .forEach(e -> retrieve(e::getName, e::getAge).call(this::printNameAge));   

コードは次のとおりです。

private void printNameAgeSalary(String name, int age, double salary) {
    System.out.format("%s %d %.0f\n", name, age, salary);
}

private void printNameAge(String name, int age) {
    System.out.format("%s %d\n", name, age);
}

public interface Consumer2<T1, T2> {
    void consume(T1 t1, T2 t2);
}

public interface Consumer3<T1, T2, T3> {
    void consume(T1 t1, T2 t2, T3 t3);
}

public interface Caller<E> {

    void call(E code);

    static <S1, S2, S3> Caller<Consumer3<S1, S2, S3>> retrieve(Supplier<S1> s1, Supplier<S2> s2, Supplier<S3> s3) {
        return (Consumer3<S1, S2, S3> code) -> code.consume(s1.get(), s2.get(), s3.get());
    }

    static <S1, S2> Caller<Consumer2<S1, S2>> retrieve(Supplier<S1> s1, Supplier<S2> s2) {
        return (Consumer2<S1, S2> code) -> code.consume(s1.get(), s2.get());
    }
}
于 2015-05-15T08:40:18.870 に答える