使用 Java 流基于字符串创建新对象

Create new Objects based on a String with Java Stream

我正在玩 Java Streams,我想知道是否有任何方法可以创建这样的代码块 ->

if(givenString.equals("productA")) {
    return new productA();
} else if(givenString.equals("productB") {
    return new productB();
} .....

像这样进入 Java 流 ->

Stream.of(givenString)
      .filter(e -> e.equal("productA)")
      .map(e -> new productA())   

我遇到了这个可行的解决方案,但我不相信...

Stream.of(givenString)
      .map(e -> e -> e.equals("productA)" ? new productA() : new productB())      
      .findAny()
      .get()

在下面的第一个示例中:


    if(givenString.equals("productA")) {
        return new productA();
    } else if(givenString.equals("productB") {
        return new productB();
    } 

您正在返回通过字符串指定的某个对象的实例。在我看来,如果您知道字符串,就可以立即创建对象,而无需使用中间方法调用。

另一种可能性是 class 名称是通过某些用户输入提供的。在这种情况下,您可能需要考虑 reflection 来完成此操作,以便您可以引用新创建的 class.

的方法和字段

无论哪种情况,我都怀疑 streams 是满足此类要求的合理方法。

您不想在流中内联执行该操作。取而代之的是,编写一个辅助方法来做到这一点:

private static Product createByString(String name) {
    // I assume Product is a common superclass
    // TODO: implement
}

现在的问题是:这个方法应该如何实现?

  1. 使用大 switch 语句。

    private static Product createByString(String name) {
        switch (name) {
            case "productA": new productA();
            case "productB": new productB();
            // ... maybe more?
            default: throw new IllegalArgumentException("name " + name + " is not a valid Product");
        }
    }
    

    专业版:字符串上的 switch 被编译成跳转表,因此您不会进行 n 字符串比较。
    缺点:你不能在运行时扩展它,你必须保持这个方法同步。

  2. 使用一个HashMap<String,Supplier<Product>>

    private static final Map<String,Supplier<Product>> productConstructors = new HashMap<>();
    static {
        productConstructors.put("productA", productA::new);
        productConstructors.put("productB", productB::new);
    }
    private static Product createByString(String name) {
        Supplier<Product> constructor = productConstructors.get(name);
        if (constructor == null) {
            // Handle this?
            throw new IllegalArgumentException("name " + name + " is not a valid Product");
        }
        return constructor.get();
    }
    

    Pro:通过一些简单的修改,您可以将新产品添加到此实现中,甚至替换它们。
    缺点:有一些适度的开销,你仍然需要维护 "productA" 和它的类型之间的映射。

  3. 使用反射。
    每个问题看起来都像钉子的好旧锤子。

    private static Product createByString(String name) {
         try {
             return Class.forName("your.pkgname. " + name).asSubclass(Product.class).getConstructor().newInstance();
         } catch (ReflectiveOperationException e) {
             throw new RuntimeException(e);
         }
    }
    

    亲:您不需要进行绑定。
    缺点:速度慢。