【问题标题】:Create new Objects based on a String with Java Stream [closed]使用 Java 流基于字符串创建新对象 [关闭]
【发布时间】:2019-08-30 11:20:17
【问题描述】:

我正在玩 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()

【问题讨论】:

  • 为什么要使用 Stream 来完成这个简单的任务。您的第一种方法有什么问题?
  • 另外,您“不相信”该方法的哪些元素。你说它有效,所以我不知道有什么建议可以解决它。
  • 好吧,我对此没有意见……我只是想探索流的可能性……
  • 我认为您将流的使用与条件检查混淆了。从问题来看,您似乎有一个字符串,您需要在其中检查值,因此 if else 块或 switch case 将是那些野兽。即使您使用的是 java 8 或更高版本,也没有规定一切都会在 Steam 中或一些新功能中。
  • Stream 不能替代逻辑条件。在您的特定情况下,您实际上得到的是 Map<String, Supplier<Product>> 而不是流。

标签: java string java-stream predicate supplier


【解决方案1】:

您不想在流中内联。相反,请编写一个辅助方法来执行此操作:

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();
    }
    

    专业版:通过一些简单的修改,您可以在此实施中添加新产品,甚至替换它们。
    缺点:有一些适度的开销,你仍然需要维护"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);
         }
    }
    

    专业人士:您无需进行绑定。
    缺点:很慢。

【讨论】:

  • 感谢您的回答!我需要静态代码块做什么?
【解决方案2】:

在下面的第一个示例中:


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

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

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

无论哪种情况,我都怀疑streams 是否适合这种要求。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-06-20
    • 1970-01-01
    • 1970-01-01
    • 2011-01-13
    • 2020-04-22
    • 2019-06-05
    • 2014-11-22
    • 1970-01-01
    相关资源
    最近更新 更多