V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
20015jjw
V2EX  ›  问与答

请问这种逻辑特别简单,但是写起来非常蛋疼的 Java 怎么办?

  •  
  •   20015jjw · 2017-12-05 11:10:21 +08:00 · 2410 次点击
    这是一个创建于 2305 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我知道各位会说换其他 Java 替代语言(Kotlin...),但是公司代码库暂时不支持。

    现在我有一堆User, 然后有个 Helper 会逐个检查这些 User,然后如果 User 的 Email 地址或者电话号码对应输入,就 return 那个 User。代码如下(手工重写的,省去了很多细节)

    public User getUserFromEmail(String email) {
      for (User user : getUsers()) {
        if (email.equals(user.getEmail())) {
          return user;
        }
      } 
    }
    
    public User getUserFromPhoneNumber(String phoneNumber) {
      for (User user : getUsers()) {
        if (phoneNumber.equals(user.getPhoneNumber())) {
          return user;
        }
      } 
    }
    

    那这俩方程基本就差一点点,所以我想把他们合并起来。我现在的想法写出来感觉非常恶心。

    public User getUserFromEmail(String email) {
      User(email, null);
    }
    
    public User getUserFromPhoneNumber(String phoneNumber) {
      getUser(null, phoneNumber);
    }
    
    private User getUser(String email, String phoneNumber) {
      String query, userInfo;
      if (email != null) {
        query = email;
      } else if (phoneNumber != null) {
        query = phoneNumber;
      } else {
        return null;
      }
      for (user : getUsers()) {
        if (email != null) {
          userInfo = user.getEmail();
        } else if (phoneNumber != null) {
          userInfo = user.getPhoneNumber();
        }
        if (query.equals(userInfo)) {
          return user;
        }
      }
    }
    

    蛋疼的地方有 2 个,一个是合并后结果比原来长很多,还有一个是这样每个循环都要做多一个 check,显得非常愚蠢,不知道各位 Java 大佬有没有什么办法可以帮到我,先谢谢了 ><

    第 1 条附言  ·  2017-12-05 12:31:51 +08:00
    忘说了,但是 Lambda 也不支持... Java 8 整个就不支持,因为项目需要支持旧版安卓...
    19 条回复    2017-12-06 00:52:38 +08:00
    hyyou2010
        1
    hyyou2010  
       2017-12-05 11:52:17 +08:00
    定义这么个东西:
    public class UserCompareItems{
    public String name;//为 null 时表示不必对这一项
    public String phone;//非 null 时表示比对这一项
    public String otherItems;
    }

    然后在 User 类中实现一个和 UserCompareItems 比较的接口
    以后只传这个类的对象来挑选 user

    ----------临时想的,没验证,不一定好,仅供参考
    cloud107202
        2
    cloud107202  
       2017-12-05 11:52:48 +08:00
    这个算是 OO 语言给思维带来的枷锁。试图从 List 中 filter 一些结果,但是要根据不同的动态条件。纯 OO 语言里不太好做,或者需要动用设计模式。FP 里就是把怎样取属性并比较这个动作(function/ first-class function ) 当成变量传进去而已。

    举个例子,边界判断要自己补充下
    https://gist.github.com/liyuntao/54bc04e963fa969b2d82903d51bfea69
    SuperMild
        3
    SuperMild  
       2017-12-05 12:16:21 +08:00 via iPhone
    电话号码不可能含 @ ,判断一下字符就可以自动选择不同的流程了
    SuperMild
        4
    SuperMild  
       2017-12-05 12:18:44 +08:00 via iPhone
    增加一个叫 getFromEmailOrPhonenumber 的 wraper
    20015jjw
        5
    20015jjw  
    OP
       2017-12-05 12:26:42 +08:00
    @cloud107202
    你的想法我挺喜欢,但是 Java 还不支持,所以很痛苦... 我大概实现了一个类似的,但是无奈效果还是感觉不如原来的,因为还是比原来的长,而且比原来的难读很多。谢谢了。
    @hyyou2010 welp,简直蛋疼... 如果就 email 和电话感觉远不要这么麻烦。
    marknote
        6
    marknote  
       2017-12-05 12:29:38 +08:00 via iPhone
    用 lambda 吧
    20015jjw
        7
    20015jjw  
    OP
       2017-12-05 12:30:48 +08:00
    @SuperMild 我也想到了,但感觉虽然这里可以用,但是换一种情况就又蛋疼了... 而且还是少不了每次循环的电话 /邮箱 check...

    ```
    for (...) {
    if (query.is_number && query.equals(User.getPhoneNumber()) {
    return user;
    } else if (query.is_email && query.equals(User.getEmail()) {
    return user;
    }
    }
    ```
    canbingzt
        8
    canbingzt  
       2017-12-05 13:01:57 +08:00
    直接 query.equals(user.getEmail()) || query.equals(user.getPhoneNumber()) 就可以了吧
    邮箱和电话号码应该不会相同吧
    zjp
        9
    zjp  
       2017-12-05 13:18:13 +08:00 via Android
    如果还有更多属性需要查找,#2 的行为模版化的方法就能体现出优势来 只是没有 lambda 写起来更长了…
    cloud107202
        10
    cloud107202  
       2017-12-05 13:22:22 +08:00
    @20015jjw 给你的代码就是 java8 的 lambda API...
    SoloCompany
        11
    SoloCompany  
       2017-12-05 13:25:15 +08:00 via iPhone
    实在用不了 j8 还可以用 org.apache.common-collections 顶一下,别想可以有多大改进,只是换一种抽象( functor 或说算子)而已
    kran
        12
    kran  
       2017-12-05 13:37:38 +08:00 via iPhone
    用反射,传字段名和值
    ssynhtn
        13
    ssynhtn  
       2017-12-05 14:44:36 +08:00
    自定义一个 Interface
    interface Matcher {
    boolean matches(User user);
    }

    通用方法
    User getUser(Matcher matcher) {
    for (User user : getUsers()) {
    if (matcher.matches(user) return user;
    }
    return null;
    }

    这是很基本的东西, 上面有人说用 lamda 也好用 stream api 的 filter 也好都是同一个道理
    这种东西在 Java 里面到处都有
    LxExExl
        14
    LxExExl  
       2017-12-05 14:51:39 +08:00 via iPhone
    没写过 java
    PHP 的话有 schema 直接 queryFrom 然后 whereEquals...

    帮顶了
    evitceted
        15
    evitceted  
       2017-12-05 15:13:16 +08:00
    rxjava
    20015jjw
        16
    20015jjw  
    OP
       2017-12-05 17:19:44 +08:00 via Android
    @cloud107202 我的意思是 java 8 不能用 很难受...
    @ssynhtn 对这个也很难读 我想到了但是写出来不可能比那俩原方程短了
    @SoloCompany 一会看看 谢谢 但是我觉得可能 @canbingzt 的办法暂时就够了 没想到这个 hhhh 谢谢啦
    yrom
        17
    yrom  
       2017-12-05 17:25:41 +08:00
    android studio 3.0 已经支持 java 8 部分特性了(尤其是 lambda )
    YellowLittleDog
        18
    YellowLittleDog  
       2017-12-05 18:20:22 +08:00 via Android
    rxjava 链起来
    20015jjw
        19
    20015jjw  
    OP
       2017-12-06 00:52:38 +08:00 via Android
    @yrom 我们的 codebase 不支持...
    @YellowLittleDog ...那也太麻烦了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3535 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 00:48 · PVG 08:48 · LAX 17:48 · JFK 20:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.