【问题标题】:What are good patterns / techniques to reduce verbosity of Java [closed]什么是减少Java冗长的好模式/技术[关闭]
【发布时间】:2009-08-09 04:18:42
【问题描述】:

Java 可能有点烦人的一件事是表达概念所需的代码量。我信奉“代码越少越好”的理念,我想知道如何编写 Java 而又不至于令人沮丧地冗长。最近,我阅读了Hidden Features of Java 问题并被介绍使用double-brace initialization 来模拟List 或Map 文字。当然,使用这种方法也有缺点,但它确实允许你用更少的字符来做某些事情,并且(如果你的格式正确的话)使代码更干净、更清晰。我想知道是否没有其他巧妙的技巧和鲜为人知的语言功能可以使我的代码更简洁。

我希望看到答案,其中包含对该技术的解释、它所替代的更详细的方式以及使用该技术的任何潜在缺点。

【问题讨论】:

标签: java design-patterns coding-style


【解决方案1】:

在 Java 7 中引入 diamond operator 之前,用于创建泛型类型的静态工厂方法可用于通过减少重复类型参数的需要来减少冗长。 (这是因为没有菱形运算符,Java 永远不会推断构造函数的类型参数,但它会推断方法调用。)Google Collections 使用这种技术,因此您可以编写:

Set<MyClassWithALongName> set = Sets.newHashSet();

代替:

Set<MyClassWithALongName> set = new HashSet<MyClassWithALongName>();

查看 Google Collections 的 ListsSetsMaps 类,了解以“new”开头的方法以获取更多示例。

除非您是为旧版本的 Java 编写代码,否则从 Java 7 开始,最好只使用菱形运算符。

【讨论】:

  • 如果您还没有使用 Google Collections,请务必使用您自己的方法!我敢肯定劳伦斯不是故意暗示其他的:)
  • 自 Java 7 起已过时。请参阅菱形运算符。
  • @user2418306 你是对的。我已经更新了答案。谢谢!
【解决方案2】:

您可能已经知道类似的一个,使用“可变参数”功能:

String[] array = new String[] {"stack", "over", "flow"};
List<String> list = Arrays.asList(array);

可以缩写

List<String> list = Arrays.asList("stack", "over", "flow");

诚然,节省不多,但它确实减少了一点冗长。 正如 Thomas 所说,列表是不可变的,因此请注意这一点。 实际上,您可以修改列表,但不能更改其长度。感谢 pimlotc 指出这一点。

【讨论】:

  • 是的!我在自己的函数中使用了可变参数,但由于某种原因,我忽略了 Arrays.asList 使用可变参数的事实。谢谢!
  • 但是小心,这个列表是不可变的。
  • 这不是真的,列表是可变的;你只是不能改变它的长度。您可以替换列表中的任何值,例如Arrays.asList("1", "2", "3").set(0, "a") 有效。
【解决方案3】:

使用像spring这样的依赖注入框架。我几乎总是对多少代码构造逻辑产生的结果感到惊讶。

【讨论】:

  • 也可以试试 Guice。 code.google.com/p/google-guice 它产生比 Spring 更短的配置(尤其是与 Spring 的 XML 配置相比),并且您可以获得编译时类型检查。
  • 好吧,我完全支持基于注释的 spring 配置,有 5 行 xml,没有代码。
  • 元编程将更通用的名称为这种技术。龙目岛项目是这种方法的另一个例子。
【解决方案4】:

我发现编写简洁的 java 最(唯一?)有效的方法是根本不编写 java。如果我需要快速编写仍然与 Java 互操作的东西,我发现 Groovy 是一个很好的选择。使用仍然编译为 JVM 字节码的更简洁的语言可能是一个很好的解决方案。虽然我没有个人经验,但我听说 Scala 在很多情况下比 Groovy 更好。

【讨论】:

  • 与其他替代方案相比,Groovy 的速度慢得要命。
【解决方案5】:

查看lambdaj。它有很多特性可以帮助你的代码更加简洁和可读。

【讨论】:

  • 这个答案太宽泛了。请给出详细代码和简洁对应的示例。如果你暗指闭包的 lambda 表示法,那么自 Java 8 以来这已经过时了。
【解决方案6】:

Fluent interfaces 可以提供帮助 - 使用构建器和方法链接在 java 中制作类似于 DSL 的东西。您最终得到的代码可能会有点难以阅读,因为它违反了 Java 的正常编码约定,例如从属性中删除 set / get。

所以在一个假的 Swing fluent 界面中,你可以这样定义一个按钮:

JButton button = Factory.button().icon(anIcon).tooltip("Wow").swing();

另一种方法是使用另一种与 JVM 很好集成的语言,例如:

【讨论】:

  • 您有提供流畅接口的 Java API 示例吗?我熟悉 RoR 的概念,也看过 FluentNHibernate,但我想看看这在 Java 世界中的“感觉”如何。无论如何,+1 提到 Scala。一种很好的语言,可以与 Java 和 JVM 完美集成。不过,我还没有在实际项目中尝试过。
  • 也许你想要Hamcrest?看看例子herehere
  • 使用另一种语言是避免而不是减少 java 的冗长。
【解决方案7】:

“closeQuietly”方法可用于 try/finally 块中关闭时的 IO 异常无趣(或不可能)的情况。

Closeable c = null;
try {
    ...
    c = openIt(...);
    ...
} finally {
    closeQuietly(c);
}

地点:

/** Close 'c' if it is not null, squashing IOExceptions */
public void closeQuietly(Closeable c) {
    if (c != null) {
        try {
            c.close();
        } catch (IOException ex) {
            // log error 
        }
    }
}

请注意,在 Java 7 及更高版本中,新的“使用资源尝试”语法使这个特定示例变得多余。

【讨论】:

  • 自 Java 7 起已过时。请参阅资源尝试。
【解决方案8】:

我发现一篇博客文章提供了一种有趣的技术,它允许在 Java 中编写映射文字,就像在 Perl、Python、Ruby 等中一样:Building your own literals in Java - Tuples and Maps 我真的很喜欢这种方法!我就在这里总结一下吧。

基本思想是创建一个泛型对类并定义将构造对的静态函数,以及来自对的可变参数数组的映射。这允许以下简洁的映射字面量定义:

Map(o("height", 3), o("width", 15), o("weight", 27));

其中o 是构造一对 T1 和 T2 对象的静态函数的名称,对于任何对象类型 T1 和 T2,Map 是构造 Map 的静态函数的名称。我不确定我是否喜欢选择Map作为地图构造函数的名称,因为它与Java接口的名称相同,但概念还是不错的。

【讨论】:

    【解决方案9】:

    静态初始化器

    示例 1(地图):

    Map<String, String> myMap = new HashMap<String, String>() {{
        put ("a", "b");
        put ("c", "d");
    }};
    

    示例 2(列表):

    List<String> myList = new ArrayList<String>() {{
        add("a");
        add("b");
        add("c");
    }};
    

    【讨论】:

    • 我不喜欢这会创建一个匿名类。
    • 你为什么不喜欢匿名课程 Ravi?我知道这种技术的缺点之一是,如果您在其封闭对象之外使用生成的 Map 或 List,您将传递对封闭对象的隐式引用。这可能会导致内存泄漏。但只要你明白这一点并小心,我看不出问题。也许这个警告应该作为一个缺点添加到答案中。
    • 是的,这不那么冗长,但您团队的初级成员可能会感到困惑。此外,它还会发出编译器警告。
    • @mR_frOg,我真的不同意这种观点。我多次听到这样的论点:“我们不能使用这种先进技术,因为它可能会使经验不足的开发人员感到困惑”。您如何建议新手获得成为高级开发人员的经验和技能?他们必须看到先进的技术来学习它们。争论的焦点应该是编码风格的优点,而不是新手能否轻松掌握它。如果您觉得其他人可能对正在发生的事情感到困惑,请在您的代码中留下评论,描述您正在做什么。
    • A. Levy:不,它缺少关键字static,所以它是一个实例初始化器,见java.sun.com/docs/books/jls/second_edition/html/…
    【解决方案10】:

    初始化不可变映射的更多 Guave 优点(我发现这比初始化可变映射更常见):ImmutableMap.of(...) variants

    Map<Service, Long> timeouts = ImmutableMap.of(
        orderService, 1500, 
        itemService, 500);
    

    【讨论】:

      【解决方案11】:

      曾经必须遍历一个集合,只是通过它的一个属性来映射它的元素吗?不用了,感谢Maps.uniqueIndex()

      private void process(List<Module> modules) {
      
          Map<String, Module> byName = Maps.uniqueIndex(modules, new Function<Module, String>() {
                  @Override public String apply(Module input) {
                      return input.getName();
                  }
              });
      

      或者如果这种情况足够频繁,则将该函数设为Modulepublic static final 成员,以便将上述内容简化为:

          Map<String, Module> byName = Maps.uniqueIndex(modules, Module.KEY_FUNCTION);
      

      【讨论】:

      • 自 Java 8 起已过时。请参阅方法参考。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-21
      • 1970-01-01
      • 2010-10-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多