Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/381.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Java流中拆分对象_Java_Java 8_Java Stream_Method Reference - Fatal编程技术网

在Java流中拆分对象

在Java流中拆分对象,java,java-8,java-stream,method-reference,Java,Java 8,Java Stream,Method Reference,我想知道是否有可能分割流中的对象。例如,对于该员工: 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 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类中-否则太容易了):

现在看起来是这样的:

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));
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));
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));
问题是,是否有可能在这样的流中放入一些代码

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
是这种情况下最漂亮的解决方案,但有时我们在现实生活中无法做到这一点,应该是lambdas的通用解决方案。

简而言之,答案是否定的,您无法做到这一点。我能想到的最短解决方案是定义自己的功能接口,如下所示:

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));
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));
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));
虽然它一点也不漂亮

我认为如果您的
someOperationWithEmployee
Employee
对象作为参数会更好

更新:对于这对值,您可以像这样使用我的免费库:

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));
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));
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));
但是,它仅限于对,因此不能以这种方式处理三个或更多的值(我不打算添加这样的函数)


我还检查了这个库,因为它集中在元组上,并且已经提供了类似的接口。然而,似乎也没有简单的方法来解决您的问题。

我不确定这是否适合您的需要,但它需要一点反射,并且不检查某些类型

您可以通过以下方式运行我的解决方案:

    Stream.of(new Employee("Adam", 38, 3000), new Employee("John", 19, 2000))
        .forEach(
                e->ArrayCaller.<TriConsumer<String, Integer, Double>>convert(e::getName, e::getAge, e::getSalary)
                                                                     .call((a, b, c) -> operation(a, b, c)));
当然,它需要以下辅助类型:

/** Extending interfaces must have a method called consume with N args */
interface NConsumer {}

/*
 * Method must be called consume for reflection.
 *
 * You can define N interfaces like this.
 */
nterface TriConsumer<A, B, C> extends NConsumer {
    void consume(A a, B b, C c);
}

interface ArrayCaller<E extends NConsumer> {
    void call(E code);
    static <T extends NConsumer> ArrayCaller<T> convert(Supplier<?>...argSuppliers) {
        final Object[] args = new Object[argSuppliers.length];
        for (int i = 0; i < argSuppliers.length; i++) {
            args[i] = argSuppliers[i].get();
        }
        return new ArrayCaller<T>() {
            @Override
            public void call(T code) {
                for (Method m: code.getClass().getMethods()) {
                    if (m.getName().equals("consume")) {
                        try {
                            m.invoke(code, args);
                        } catch (IllegalAccessException
                                | IllegalArgumentException
                                | InvocationTargetException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            }
        };
    }
}
/**扩展接口必须有一个名为consume的方法,并带有N个参数*/
接口NConsumer{}
/*
*必须调用方法进行反射。
*
*您可以这样定义N个接口。
*/
界面三角消费者{
无效消耗(A、B、C);
}
接口阵列调谐器{
无效呼叫(E代码);
静态ArrayCaller转换(供应商…argSuppliers){
最终对象[]args=新对象[argSuppliers.length];
对于(int i=0;i
这里以自己的方式重新设计,没有任何反思。使用静态导入时,可以这样使用:

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());
    }
}
private void printNameAgeAlary(字符串名称、整数年龄、双倍工资){
系统输出格式(“%s%d%.0f\n”,姓名、年龄、工资);
}
私有void printNameAge(字符串名,int-age){
System.out.format(“%s%d\n”,名称,年龄);
}
公共接口使用者2{
空洞消耗(T1,T2);
}
公共接口使用者3{
空洞消耗(T1、T2、T3);
}
公共接口调用者{
无效呼叫(E代码);
静态调用方检索(供应商s1、供应商s2、供应商s3){
return(Consumer3 code)->code.consumer(s1.get()、s2.get()、s3.get());
}
静态调用方检索(供应商s1、供应商s2){
return(Consumer2代码)->code.consumer(s1.get(),s2.get());
}
}

我相信这将是一个更大的麻烦。是的,我知道javaslang,但似乎它在这里也帮不上忙。@Tagir在我看来,jOOL是一个宽泛而繁重的解决方案,因为只有Function3 FunctionN实现。也许有一些小的库可以用于这种特殊和流行的情况(我指的是具有多个参数的函数)?我想最好自己为您的项目创建这样的接口。在我看来,目前这种接口还没有“事实上的标准”。你可以使用
this::someOperationWithEmployee
,这样会更好一些。@StuartMarks,当然,我通常是这样写的,但OP要求使用lambda符号。我想在回答中明确显示
someOperationWithEmployee
方法需要多少参数。我认为最好为1、2、3等参数定义单独的方法,直到达到合理的限制,这样您就可以进行编译时类型检查,而不必显式强制转换。而且它的工作速度会大大加快。对,我考虑过为预定义的XCosumer接口调用
call
方法,但对于NConsumer,也可以使用用户定义的XCosumer接口调用任何其他数量的参数。编辑:我将ArrayCaller设置为泛型,这样您就可以键入它,而无需再键入lambda。@TagirValeev为了加快速度,您还可以缓存反射,保存按接口类型(如TriConsumer)索引的方法对象。通过一些包装和重命名,它允许以以下方式写入:
Stream.of(…).forEach(e->retrieve(e::getName,e::getAge,e::getSalary)。然后调用(this::someOperationWithEmployee))与当前比较:
Stream.of(..).forEach(e->someOperationWithEmployee(e.getName,e.getAge(),e.getSalary))