1. 概述

本教程将探讨如何为不同场景生成模拟数据。我们将学习如何使用 Datafaker 并通过多个示例深入理解其用法。

2. 发展历程

Datafaker 是 Javafaker 的现代分支版本。 它迁移至 Java 8 并进行了多项改进,显著提升了库的性能。但当前 API 基本保持不变,因此从 Javafaker 迁移到 Datafaker 不会遇到兼容性问题。本文提供的所有示例均适用于 Datafaker 1.6.0 版本。

当前 Datafaker API 与 Javafaker 兼容。因此本文将重点介绍差异点和改进特性。

首先添加 Maven 依赖:

<dependency>
    <groupId>net.datafaker</groupId>
    <artifactId>datafaker</artifactId>
    <version>1.6.0</version>
</dependency>

3. 数据提供者

Datafaker 的核心组件是数据提供者。这是一组特殊类,使数据生成更便捷。这些类由包含真实数据的yml 文件支持。Faker 方法和表达式直接或间接使用这些文件生成数据。后续章节将深入解析这些方法和指令的工作原理。

4. 新增数据生成模式

Datafaker 和 Javafaker 都支持基于模式生成数据。Datafaker 新增了 templatify, exemplify, options, date, csv, json 等指令。

4.1. Templatify 模板化

templatify 指令接收多个参数:

  1. 基础字符串
  2. 待替换字符
  3. 随机替换选项列表
public class Templatify {
    private static Faker faker = new Faker();

    public static void main(String[] args) {
        System.out.println("表达式: " + getExpression());
        System.out.println("带占位符表达式: " + getExpressionWithPlaceholder());
    }

    static String getExpression() {
        return faker.expression("#{templatify 'test','t','j','r'}");
    }

    static String getExpressionWithPlaceholder() {
        return faker.expression("#{templatify '#ight', '#', 'f', 'l', 'm', 'n'}");
    }
}

⚠️ 虽然可以直接使用基础字符串,但可能产生意外结果(会替换所有匹配字符)。建议使用占位符(仅在特定位置出现的字符):

表达式: resj
带占位符表达式: night

当存在多个可替换位置时,每次都会随机选择。虽然支持字符串替换,但文档未明确说明,建议谨慎使用。

4.2. Examplify 示例化

该指令根据提供的示例生成随机值

  • 小写/大写字母 → 随机同类字母
  • 数字 → 随机数字
  • 特殊字符保持不变(便于创建格式化字符串)
public class Examplify {
    private static Faker faker = new Faker();

    public static void main(String[] args) {
        System.out.println("字符串表达式: " + getExpression());
        System.out.println("数字表达式: " + getNumberExpression());
    }

    static String getExpression() {
        return faker.expression("#{examplify 'Cat in the Hat'}");
    }

    static String getNumberExpression() {
        return faker.expression("#{examplify '123-123-123'}");
    }
}

输出示例:

字符串表达式: Lvo lw ero Qkd
数字表达式: 707-657-434

4.3. Regexify 正则化

创建格式化字符串的更灵活方式:

public class Regexify {
    private static Faker faker = new Faker();

    public static void main(String[] args) {
        System.out.println("表达式: " + getExpression());
        System.out.println("方法调用: " + getMethodExpression());
    }

    static String getExpression() {
        return faker.expression("#{regexify '(hello|bye|hey)'}");
    }

    static String getMethodExpression() {
        return faker.regexify("[A-D]{4,10}");
    }
}

输出示例:

表达式: bye
方法调用: DCCC

4.4. Options 选项

从指定列表中随机选择选项(虽然可用 regexify 实现,但独立指令更便捷):

public class Option {
    private static Faker faker = new Faker();

    public static void main(String[] args) {
        System.out.println("表达式1: " + getFirstExpression());
        System.out.println("表达式2: " + getSecondExpression());
        System.out.println("正则对比: " + getThirdExpression());
    }

    static String getFirstExpression() {
        return faker.expression("#{options.option 'Hi','Hello','Hey'}");
    }

    static String getSecondExpression() {
        return faker.expression("#{options.option '1','2','3','4','*'}");
    }

    static String getThirdExpression() {
        return faker.expression("#{regexify '(Hi|Hello|Hey)'}");
    }
}

输出示例:

表达式1: Hey
表达式2: 4
正则对比: Hello

❌ 当选项过多时,建议创建自定义提供者。

4.5. CSV 生成

生成 CSV 格式数据。⚠️ 注意:该指令由两个重载方法处理,容易混淆

public class Csv {
    private static Faker faker = new Faker();

    public static void main(String[] args) {
        System.out.println("基础用法:\n" + getFirstExpression());
        System.out.println("高级用法:\n" + getSecondExpression());
    }

    static String getFirstExpression() {
        String expr = "#{csv '4','name_column','#{Name.first_name}','last_name_column','#{Name.last_name}'}";
        return faker.expression(expr);
    }

    static String getSecondExpression() {
        String expr = "#{csv ',','\"','true','4','name_column','#{Name.first_name}','last_name_column','#{Name.last_name}'}";
        return faker.expression(expr);
    }
}

输出示例:

基础用法:
"name_column","last_name_column"
"Riley","Spinka"
"Lindsay","O'Conner"
"Sid","Rogahn"
"Prince","Wiegand"

高级用法:
"name_column","last_name_column"
"Jen","Schinner"
"Valeria","Walter"
"Mikki","Effertz"
"Deon","Bergnaum"

✅ 这是生成外部程序所需模拟数据的绝佳方式。

4.6. JSON 生成

通过表达式生成 JSON 数据:

public class Json {
    private static final Faker faker = new Faker();

    public static void main(String[] args) {
        System.out.println(getExpression());
    }

    static String getExpression() {
        return faker.expression(
          "#{json 'person'," + "'#{json ''first_name'',''#{Name.first_name}'',''last_name'',''#{Name.last_name}''}'," +
          "'address'," + "'#{json ''country'',''#{Address.country}'',''city'',''#{Address.city}''}'}");
    }
}

输出示例:

{"person": {"first_name": "Dorian", "last_name": "Simonis"}, "address": {"country": "Cameroon", "city": "South Ernestine"}}

4.7. 方法调用

所有表达式本质上都是方法调用,方法名和参数以字符串形式传递。因此前述指令都有对应方法:

public class MethodInvocation {
    private static Faker faker = new Faker();

    public static void main(String[] args) {
        System.out.println("方法调用: " + getNameFromMethod());
        System.out.println("表达式调用: " + getNameFromExpression());
    }

    static String getNameFromMethod() {
        return faker.name().firstName();
    }

    static String getNameFromExpression() {
        return faker.expression("#{Name.first_Name}");
    }
}

表达式可直接调用 Faker 对象的任意数据生成方法(方法名不区分大小写,但建议参考文档确认)。

还支持带参数的方法调用

public class MethodInvocationWithParams {
    public static int MIN = 1;
    public static int MAX = 10;
    public static String UNIT = "SECONDS";
    private static Faker faker = new Faker();

    public static void main(String[] args) {
        System.out.println("方法调用: " + getDurationFromMethod());
        System.out.println("表达式调用: " + getDurationFromExpression());
    }
    static Duration getDurationFromMethod() {
        return faker.date().duration(MIN, MAX, UNIT);
    }

    static String getDurationFromExpression() {
        return faker.expression("#{date.duration '1', '10', 'SECONDS'}");
    }
}

表达式返回值固定为 String 类型,限制了后续操作:

方法调用: PT6S
表达式调用: PT4S

5. 集合生成

集合功能可生成包含模拟数据的列表,元素类型可不同。集合类型由所有元素类的最具体父类决定。生成《星球大战》和《星际迷航》角色列表:

public class Collection {
    public static int MIN = 1;
    public static int MAX = 100;
    private static Faker faker = new Faker();

    public static void main(String[] args) {
        System.out.println(getFictionalCharacters());
    }

    static List<String> getFictionalCharacters() {
        return faker.collection(
          () -> faker.starWars().character(),
          () -> faker.starTrek().character())
            .len(MIN, MAX)
            .generate();
    }
}

输出示例: [Luke Skywalker, Wesley Crusher, Jean-Luc Picard, Greedo, Hikaru Sulu, William T. Riker]

当所有提供者返回 String 时,集合类型为 String。混合类型示例:

public class MixedCollection {
    public static int MIN = 1;
    public static int MAX = 20;
    private static Faker faker = new Faker();

    public static void main(String[] args) {
        System.out.println(getMixedCollection());
    }

    static List<? extends Serializable> getMixedCollection() {
        return faker.collection(
        () -> faker.date().birthday(),
        () -> faker.name().fullName())
          .len(MIN, MAX)
          .generate();
    }
}

String 和 Timestamp 的最具体父类是 Serializable

[1964-11-09 15:16:43.0, Devora Stamm DVM, 1980-01-11 15:18:00.0, 1989-04-28 05:13:54.0,
  2004-09-06 17:11:49.0, Irving Turcotte, Sherita Durgan I, 2004-03-08 00:45:57.0, 1979-08-25 22:48:50.0,
  Manda Hane, Latanya Hegmann, 1991-05-29 12:07:23.0, 1989-06-26 12:40:44.0, Kevin Quigley]

6. 总结

Datafaker 是 Javafaker 的改进版本。本文介绍了 Datafaker 1.6.0 的新数据生成方式。要深入了解该库,建议参考官方文档GitHub 仓库

本文代码示例可在 GitHub 获取。


原始标题:Introduction to Datafaker