如何使用带有三个参数的静态构造函数引用Java 8函数(没有make TriFunction)?

时间:2015-08-09 12:56:58

标签: java-8

我目前正在玩Java 8,我发现了Function的问题。我想知道是否有办法使用带有树参数的函数的函数引用(name :: methode)而不声明新的功能接口(即TriFunction)。

我尝试用currying方式,但它不起作用。

我有三个班级:

Person.class

public class Person {
    public enum Sex {
        MALE, FEMALE
    }

    private String firstName;
    private String lastName;
    private Sex gender;

    public Person(String firstName, String lastName, Sex gender) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.gender = gender;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public Sex getGender() {
        return gender;
    }
}

PersonFactory

public class PersonFactory {
    public static Person create(String firstName, String lastName, String gender) {
        // Check firstName Parameter
        if(firstName == null || firstName.isEmpty()) {
            throw new IllegalArgumentException("The firstName argument expect to not be null or empty");
        }

        // Check lastName Parameter
        if(lastName == null || lastName.isEmpty()) {
            throw new IllegalArgumentException("The lastName argument expect to not be null or empty");
        }

        // Check gender Parameter
        if(gender == null || gender.isEmpty()) {
            throw new IllegalArgumentException("The gender argument expect to not be null or empty");
        } else {
            switch(gender) {
            case "M":
                return new Person(firstName, lastName, Sex.MALE);
            case "F":
                return new Person(firstName, lastName, Sex.FEMALE);
            default:
                throw new IllegalArgumentException("The gender parameter is supposed to be either 'M' for male or 'F' for Female");
            }
        }
    }
}

CsVPersonParser

public class CsvPersonParser {
    public Person parseLine(String line, String separator, Function<String, Function<String, Function<String, Person>>> creator) {
        String[] separedLine = line.split(separator);
        String firstName = separedLine[0];
        String lastName = separedLine[1];
        String gender = separedLine[2];
        return creator.apply(firstName).apply(lastName).apply(gender);
    }
}

这是我的主要课程:

public class App {
    public static void main(String[] args) {
        final String IMAGINARY_CSV_FILE_LINE = "Jean,Dupont,M";

        CsvPersonParser csvParser = new CsvPersonParser();
        csvParser.parseLine("blabla", ",", PersonFactory::create);
    }
}

编译器显示:PersonFactory类型没有定义适用于此处的create(String)

这似乎很合乎逻辑。我没有解决方案。有人可以帮助我吗?

2 个答案:

答案 0 :(得分:3)

  

我想知道为什么没有创造新事物就没有办法做到这一点。

三功能可能相当复杂。我建议您使用builder来创建一个人。

主要原因是,您没有修改参数排序,您可以扩展您的人员。当你使用三元组时,所有参数都是字符串,通常很难说哪个参数是第一个/第二个/第三个。当你想为一个人添加一个地址时,使用像TriFunction这样的泛型类就更难了。

我的建议:

public interface PersonBuilder {
    PersonBuilder withFirstName(String firstName);

    PersonBuilder withLastName(String lastName);

    PersonBuilder withGender(String gender);

    Person create();
}

具体实施:

public class DefaultPersonBuilder implements PersonBuilder {

    private String firstName;
    private String lastName;
    private String gender;

    @Override
    public PersonBuilder withFirstName(String firstName) {
        this.firstName = firstName;
        return this;
    }

    @Override
    public PersonBuilder withLastName(String lastName) {
        this.lastName = lastName;
        return this;
    }

    @Override
    public PersonBuilder withGender(String gender) {
        this.gender = gender;
        return this;
    }

    @Override
    public Person create() {
        // Check firstName Parameter
        if (firstName == null || firstName.isEmpty()) {
            throw new IllegalArgumentException("The firstName argument expect to not be null or empty");
        }

        [... your implementation using the fields]
    }
}

您的解析器方法:

public Person parseLine(String line, String separator, PersonBuilder person) {
    String[] separedLine = line.split(separator);
    String firstName = separedLine[0];
    String lastName = separedLine[1];
    String gender = separedLine[2];
    return person.withFirstName(firstName).withLastName(lastName).withGender(gender).create();
}

现在您可以更改参数顺序或向人添加新字段,而无需创建包含10个参数的函数。解析器接口现在也更简单。

答案 1 :(得分:0)

没有办法做到我想要的。然而,另外两种解决方案是可能使用lambda而不是PersonFactory::create或创建一个新的功能接口。

结果如下:

新功能界面

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

使用我的新功能界面添加函数parseLine

public class CsvPersonParser {

    // Currying style
    public Person parseLine(String line, String separator, Function<String, Function<String, Function<String, Person>>> creator) {
        String[] separedLine = line.split(separator);
        String firstName = separedLine[0];
        String lastName = separedLine[1];
        String gender = separedLine[2];
        return creator.apply(firstName).apply(lastName).apply(gender);
    }

    // New Functionnal interface style
    public Person parseLine(String line, String separator, TriFunction<String, String, String, Person> creator) {
        String[] separedLine = line.split(separator);
        String firstName = separedLine[0];
        String lastName = separedLine[1];
        String gender = separedLine[2];
        return creator.apply(firstName, lastName, gender);
    }
}

我的主要课程有解决方案

public class App {
    public static void main(String[] args) {
        final String DATA_FILE_SEPARATOR = ",";
        final String FAKE_CSV_LINE = "Jean,Dupont,M";

        CsvPersonParser csvParser = new CsvPersonParser();
        Person person;

        // Use curryling style
        person = csvParser.parseLine(FAKE_CSV_LINE, DATA_FILE_SEPARATOR, f -> l -> g -> PersonFactory.create(f, l, g));
        System.out.println("Currying style : " + person.getFirstName() + " " + person.getLastName() + " " + person.getGender());

        // Use new functionnal interface
        person = csvParser.parseLine(FAKE_CSV_LINE, DATA_FILE_SEPARATOR, PersonFactory::create);
        System.out.println("TriFunction style : " + person.getFirstName() + " " + person.getLastName() + " " + person.getGender());

        // Use lambda style
        person = csvParser.parseLine(FAKE_CSV_LINE, DATA_FILE_SEPARATOR, (a,b,c) -> PersonFactory.create(a, b, c));
        System.out.println("Lambda style : " + person.getFirstName() + " " + person.getLastName() + " " + person.getGender());
    }
}