【问题标题】:Chaining order in Guava番石榴中的链式顺序
【发布时间】:2011-06-25 13:00:13
【问题描述】:

我对 Guava 和它的风格有点陌生。我肯定在挖掘它,但我一直绊倒的一件事是链式方法的顺序。我似乎遇到这个问题最多的地方是使用复合Orderings 时。我必须不断问自己以下问题:

  • natural 去哪儿了?
  • nullFirst(或最后一个)去哪里了?
  • 哪个nullsFirst 做什么? (在下面的示例中,一个用于主机,一个用于姓氏,一个用于名字?)

这是我刚刚研究的一个示例。它看起来很麻烦,我只是不确定我是否把它们放在一起正确。我有一些 JUnit 来测试它,看起来还不错,但总是有那些古怪的边界情况。

Ordering<Host> lastNameThenFirstNameOrdering = Ordering.natural().nullsFirst().onResultOf(new Function<Host, String>() {
    public String apply(Host host) {
        return host.getLastName();
    }}).compound(Ordering.natural().nullsFirst().onResultOf(new Function<Host, String>() {
    public String apply(Host host) {
        return host.getFirstName();
    }})).nullsFirst();

至于一个实际的问题:这些事情如何执行是否有明确的规则?这似乎是从后到先的,但我很难说清楚。

编辑:只是想指出我试图替换的大而丑陋的代码:

    Ordering<Host> ordering2 = new Ordering<Host>() {
        public int compare(Host host1, Host host2) {
            if (host1 == null || host2 == null) {
                return host1 == host2 ? 0 : ((host1 == null) ? -1 : 1); 
            }
            if(host1.getLastName() != null || host2.getLastName() != null){
                if (host1.getLastName() == null) {
                    return -1;
                } else if (host2.getLastName() == null) {
                    return 1;
                }

                if (host1.getLastName().compareTo(host2.getLastName()) != 0) {
                    return host1.getLastName().compareTo(host2.getLastName());
                }
            }

            if (host1.getFirstName() == null) {
                return -1;
            } else if (host2.getFirstName() == null) {
                return 1;
            }

            return host1.getFirstName().compareTo(host2.getFirstName());
        }};

【问题讨论】:

  • 或者这太乱了甚至不值得?也许我应该打破两个子排序,并以更具表现力的方式组合它们..
  • 方法链接旨在使代码在某些情况下更具可读性。在这种情况下,它会伤害您的代码、该代码的未来维护者以及阅读您问题的每个人的眼睛
  • 您是否建议我应该通过自定义实现来做到这一点?我不确定这是否不那么令人眼花缭乱:(添加到帖子中)

标签: java guava method-chaining


【解决方案1】:

我认为你的做法是正确的,但非常丑陋。试试这个以提高可读性:

使用枚举

将函数移动到实现Function&lt;Host, String&gt; 的枚举中。每个枚举项都可以提供自己的实现。

enum HostFunctions implements Function<Host, String>{
    GETFIRSTNAME{

        @Override
        public String apply(final Host host){
            return host.getFirstName();
        }
    },
    GETLASTNAME{

        @Override
        public String apply(final Host host){
            return host.getLastName();
        }
    }

}

缩进你的代码

现在引用这些枚举函数并正确缩进您的代码。这就是它的样子:

final Ordering<Host> orderingByLastAndFirstName =
    Ordering
        .natural()
        .nullsFirst()
        .onResultOf(HostFunctions.GETLASTNAME)
        .compound(
            Ordering
                .natural()
                .nullsFirst()
                .onResultOf(HostFunctions.GETFIRSTNAME))
        .nullsFirst();

我想说这让一切变得更容易理解。

IDE 配置

关于适当的缩进(至少如果你使用 Eclipse),请看这个问题:

How to indent the fluent interface pattern “correctly” with eclipse?

枚举作为函数

关于枚举:这称为枚举单例模式。 Guava 家伙在他们的代码库中使用它。阅读 on wikipediaEffective Java,第 3 项了解它。虽然这些来源都谈到了单项枚举,但这里的方法几乎相同。

【讨论】:

  • 感谢有关枚举单例模式的提醒。我看到了布洛赫博士在他描述的地方发表的演讲。它非常有用——而且很聪明。
【解决方案2】:

每个链接调用都将先前的顺序“包装”成一个新的顺序,所以你是对的,执行顺序可以被认为是“向后”。

我编写并查看了 Ordering 类,但我仍然需要经常停下来思考 nullsFirst()、onResultOf() 和 reverse() 的正确交错!

【讨论】:

  • 凯文,听到这让我对自己感觉好多了!从“包装”的角度考虑它突然使事情变得非常清楚。 :)
【解决方案3】:

假设您必须能够处理null 主机、名字和姓氏,以下是我的偏好。对我来说,似乎非null 的名字和姓氏应该是Host 类的要求。您通常应该尽量避免允许集合包含 null 对象。

Ordering<Host> lastNameFirstNameOrdering = new Ordering<Host>() {
  @Override public int compare(Host left, Host right) {
    return ComparisonChain.start()
      .compare(left.getLastName(), right.getLastName(), Ordering.natural().nullsFirst())
      .compare(left.getFirstName(), right.getFirstName(), Ordering.natural().nullsFirst())
      .result();
  }
}.nullsFirst();

或者,我会采用类似于 Sean 的方法,但为了可读性而将其分解。

Ordering<Host> lastNameOrder = Ordering.natural().nullsFirst()
    .onResultOf(Host.LAST_NAME);
Ordering<Host> firstNameOrder = Ordering.natural().nullsFirst()
    .onResultOf(Host.FIRST_NAME);
Ordering<Host> orderingByLastAndFirstName =
     lastNameOrder.compound(firstNameOrder).nullsFirst();

请记住,您还可以将这些单独的排序设置为类的静态最终字段,以便在像Host.LAST_NAME_ORDER 这样排序时在任何地方轻松使用它们。

【讨论】:

  • 如果您要求主机的名字和姓氏不为空,如果主机没有这两个名称部分,您将选择哪个值(考虑到某些数据库不区分空和空字符串)?请参阅kalzumeus.com/2010/06/17/…,了解关于人名的常见和不常见的误解。
猜你喜欢
  • 2015-03-11
  • 2012-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多