Validation

Vavr Validation

Vavr 将 Applicative Functor 的概念从函数式编程世界带到了 Java 中。用最简单的话来说,应用型 Functor 使我们能够执行一系列的操作,同时积累结果。vavr.control.Validation 这个类有利于错误的积累。请记住,通常情况下,一个程序一旦遇到错误就会终止。

但是,Validation 会继续处理和积累错误,让程序以批处理的方式对其进行处理。考虑到我们正在按姓名和年龄注册用户,我们要先接受所有输入,并决定是创建一个 Person 实例还是返回一个错误列表。这就是我们的 Person 类。

public class Person {
    private String name;
    private int age;

    // standard constructors, setters and getters, toString
}

接下来,我们创建一个名为 PersonValidator 的类。每个字段都将由一个方法进行验证,另一个方法可以用来将所有结果合并成一个 Validation 实例。

class PersonValidator {
    String NAME_ERR = "Invalid characters in name: ";
    String AGE_ERR = "Age must be at least 0";

    public Validation<Seq<String>, Person> validatePerson(
      String name, int age) {
        return Validation.combine(
          validateName(name), validateAge(age)).ap(Person::new);
    }

    private Validation<String, String> validateName(String name) {
        String invalidChars = name.replaceAll("[a-zA-Z ]", "");
        return invalidChars.isEmpty() ?
          Validation.valid(name)
            : Validation.invalid(NAME_ERR + invalidChars);
    }

    private Validation<String, Integer> validateAge(int age) {
        return age < 0 ? Validation.invalid(AGE_ERR)
          : Validation.valid(age);
    }
}

年龄的规则是它应该是一个大于 0 的整数,而名字的规则是它不应该包含特殊字符。

@Test
public void whenValidationWorks_thenCorrect() {
    PersonValidator personValidator = new PersonValidator();

    Validation<List<String>, Person> valid =
      personValidator.validatePerson("John Doe", 30);

    Validation<List<String>, Person> invalid =
      personValidator.validatePerson("John? Doe!4", -1);

    assertEquals(
      "Valid(Person [name=John Doe, age=30])",
        valid.toString());

    assertEquals(
      "Invalid(List(Invalid characters in name: ?!4,
        Age must be at least 0))",
          invalid.toString());
}

一个有效的值包含在 Validation.Valid 实例中,一个验证错误的列表包含在 Validation.Invalid 实例中。所以任何验证方法都必须返回两者之一。

Links

上一页
下一页