Java 番石榴链序

Java 番石榴链序,java,guava,method-chaining,Java,Guava,Method Chaining,我对番石榴有点陌生,这是我的风格。我肯定是在挖掘它,但有一件事我经常被绊倒,那就是链式方法的顺序。我发现这个问题最多的地方是在使用复合排序时。我必须不断地问自己这样的问题: natural去哪里了 nullFirst(或last)在哪里 哪个nullsFirst做什么?(在下面的示例中,一个代表主机,一个代表姓氏,一个代表名字?) 这是一个我刚刚研究的例子。它看起来很笨重,我只是不确定我是否把它放在一起了。我有一些JUnits来测试它,看起来还可以,但总有一些奇怪的边界情况 Ordering

我对番石榴有点陌生,这是我的风格。我肯定是在挖掘它,但有一件事我经常被绊倒,那就是链式方法的顺序。我发现这个问题最多的地方是在使用复合
排序时。我必须不断地问自己这样的问题:

  • natural
    去哪里了
  • nullFirst
    (或last)在哪里
  • 哪个
    nullsFirst
    做什么?(在下面的示例中,一个代表主机,一个代表姓氏,一个代表名字?)
这是一个我刚刚研究的例子。它看起来很笨重,我只是不确定我是否把它放在一起了。我有一些JUnits来测试它,看起来还可以,但总有一些奇怪的边界情况

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 lastNameThenFirstNameOrdering=Ordering.natural().nullsFirst().onResultOf(新函数(){
公共字符串应用(主机){
返回host.getLastName();
}}).component(Ordering.natural().nullsFirst().onResultOf(新函数()){
公共字符串应用(主机){
返回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());
        }};
ordering2=新订单(){
公共整数比较(主机主机1、主机2){
if(host1==null | | host2==null){
返回host1==host2?0:((host1==null)?-1:1);
}
if(host1.getLastName()!=null | | host2.getLastName()!=null){
if(host1.getLastName()==null){
返回-1;
}else if(host2.getLastName()==null){
返回1;
}
如果(host1.getLastName().compareTo(host2.getLastName())!=0){
返回host1.getLastName().compareTo(host2.getLastName());
}
}
if(host1.getFirstName()==null){
返回-1;
}else if(host2.getFirstName()==null){
返回1;
}
返回host1.getFirstName().compareTo(host2.getFirstName());
}};

我认为你所做的是正确的,但非常丑陋。请尝试以下方法以提高可读性:

使用枚举 将函数移动到实现
函数的枚举中
。每个枚举项都可以提供自己的实现

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

}
enum主机函数实现函数{
GETFIRSTNAME{
@凌驾
公共字符串应用(最终主机){
返回host.getFirstName();
}
},
GETLASTNAME{
@凌驾
公共字符串应用(最终主机){
返回host.getLastName();
}
}
}
缩进代码 现在引用那些枚举函数并正确缩进代码。这就是它的样子:

final Ordering<Host> orderingByLastAndFirstName =
    Ordering
        .natural()
        .nullsFirst()
        .onResultOf(HostFunctions.GETLASTNAME)
        .compound(
            Ordering
                .natural()
                .nullsFirst()
                .onResultOf(HostFunctions.GETFIRSTNAME))
        .nullsFirst();
最终订单OrderingByStandfirstName=
订购
.natural()
.nullsFirst()
.onResultOf(HostFunctions.GETLASTNAME)
.化合物(
订购
.natural()
.nullsFirst()
.onResultOf(HostFunctions.GETFIRSTNAME))
.nullsFirst();
我想说这让一切都更容易理解

IDE配置 关于正确的缩进(至少如果您使用Eclipse),请参见以下问题:

枚举作为函数 关于枚举:这称为枚举单例模式。番石榴的家伙们在他们的代码库中使用它。阅读相关内容,或在第3项中阅读。虽然这两个源都谈到了单项枚举,但这里的方法几乎相同。

每个链接调用都是将以前的顺序“包装”到新的顺序中,因此您是对的,执行顺序可以被认为是“向后的”


我编写并审阅了Ordering类,但我仍然必须经常停下来仔细研究nullsFirst()和onResultOf()与reverse()的正确交错

假设您必须能够处理
null
hosts、first name和last name,那么我更愿意这样做。在我看来,非
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();
排序lastNameFirstNameOrdering=新排序(){ @覆盖公共整数比较(主机左侧、主机右侧){ 返回ComparisonChain.start() .compare(left.getLastName()、right.getLastName()、Ordering.natural().nullsFirst()) .compare(左.getFirstName(),右.getFirstName(),Ordering.natural().nullsFirst()) .result(); } }.nullsFirst();
或者,我会采取一种类似于肖恩的方法,但为了可读性,我会将内容分解

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();
排序lastNameOrder=Ordering.natural().nullsFirst() .onResultOf(主机名); Ordering firstNameOrder=Ordering.natural().nullsFirst() .onResultOf(主机名); 订购OrderingByStandFirstName= 复合(firstNameOrder).nullsFirst();
请记住,您还可以将这些单独的排序设置为类的静态最终字段,这样您就可以在排序时方便地在任何地方使用它们,比如
Host.LAST\u NAME\u ORDER

,或者这太乱了,不值得吗?也许我应该把这两个子顺序分开,以一种更具表现力的方式组合起来。.方法链的设计是为了在某些情况下使代码更具可读性。在这种情况下,它损害了您的代码、该代码的未来维护者以及阅读您的问题的所有人的眼睛。您是否建议我应该通过自定义实现来实现这一点?我不确定这是否会让人更眼花缭乱:(添加到帖子中)感谢大家对enum单曲的关注