【问题标题】:Best practice for returning multiple values in Java?在 Java 中返回多个值的最佳实践?
【发布时间】:2013-05-12 15:14:40
【问题描述】:

今天,我在登录表单后面添加了额外的安全检查,以减缓暴力攻击。我有多个登录表单,并制作了一个易于调用的函数,该函数执行所有检查,然后返回结果。

public static ValidateLoginResult validateLogin(HttpServletRequest request, String email, String password) {

问题是结果不是单个值,结果包括:

boolean ok
String errorMessage
boolean displayCaptcha

为此,我创建了一个新类。这一切都很好。

但我经常有方便的实用函数返回多个值,并且开始发现每次为结果创建一个新类有点烦人。

有没有更好的方法来返回多个值?还是我只是懒惰? :)

【问题讨论】:

  • 没有,但你并不懒惰 :) 这对我来说也很麻烦。
  • 不要新建类,改用generic classes
  • 新类记录语义,编译时检查返回值。为了可维护性,值得花时间。
  • 懒惰可以提高效率:)
  • 三年后才有同样的感受。我落后了多少:(

标签: java function return


【解决方案1】:

不,这种结构在 Java 中不存在,但您可以查看JavaTuples library,它可能适合您的需求并提供非常优雅的解决方案。使用Triplet<Boolean, String, Boolean>

【讨论】:

  • 但是通过一个小类,您可以使用 getter 访问成员,或者使值可选。
  • return new Triplet<Boolean, String, Boolean>(actual values) 也不是优雅的光辉典范:)
  • 这其实是个相当热门的话题:stackoverflow.com/questions/156275/…
  • @Marko Topolnik :当然,但它在许多情况下很容易重复使用,并且只要 new MyCustomObject(value1, value2, value3) :-)
  • 所以如果你的返回 Triplet 对象的方法现在需要返回可选的第 4 位数据,你必须将返回类型从 Triplet 更改为 Quartet?不用了,谢谢。我宁愿只滚动一个 ReturnObject,我可以在不破坏客户端代码的情况下添加另一个属性。
【解决方案2】:

不确定“最佳实践”,但务实的选择是返回Map<String, String>?例如

myMap.put("result", "success");
myMap.put("usernameConfirmed", "bigTom");

return myMap;

可能会违反一百万个 OO 原则,但我听说您希望避免结果类的泛滥。

您也可以使用 Map<String, Object> 并对存储对象进行更严格的类型检查:字符串、布尔值、日期等。

【讨论】:

  • 如果使用枚举作为键值,您可以避免拼写错误和自文档。
【解决方案3】:

您可以定义一个Pair<A, B> 类和一个Triplet<A, B, C> 类,这将解决返回2 和3 值的问题,同时确保类型安全。在这种特殊情况下,签名可以是

public static boolean validateLogin(HttpServletRequest request,
            String email, String password, Pair<Message, Boolean> outputIfOk);

或者更好的是,在 servlet 上下文中,设置一些有据可查的请求属性可能是有意义的。

如果您发现自己经常需要特殊的类来返回结果,您很可能可以重构这些类以共享一个共同的祖先(例如,拥有一个包含“ok”和“message”字段的 RequestStatus)。

除此之外,是的,您很懒惰——自定义类总是比 Pairs 和 Triplets 更具自我记录性。

【讨论】:

  • 好分析器,org.apache.commons.lang3.tuple 的包中还有一个 ImmutablePair
【解决方案4】:

我真的想不出比将它们封装在一个类中更好、更简洁、更面向对象的方法来从函数返回多个值。

理想情况下,您要返回的多个值在概念上都是同一个类的一部分,因此以这种方式对它们进行分组是有意义的;如果他们不这样做,那么您可能应该将您的函数分解为一些较小的函数,这些函数在函数本身之外返回您需要的每个值。

据我所知,一些 IDE 还具有帮助在一个类中封装多个值的功能:例如,Eclipse 有 Refactor --&gt; Extract class...

【讨论】:

  • 这与面向对象无关;它主要是关于 Java 的静态类型和弱泛型。 JavaScript 是面向对象的,不需要为每个元组使用另一个类。
  • 似乎每个 Java 程序员都想为所有东西创建一个对象......好的 ol' 数据有什么问题?
  • Java 是否甚至为您提供了开箱即用的替代方案?也许这不是程序员的错。
【解决方案5】:

您可以返回一个 Object[] 数组,java 自动装箱,因此它更易于使用。如果只是为了短距离切换,为什么不呢。 Ofc 有风险,可能的类转换问题,nullchecks 等

但它易于编写和使用。

再一次,一个静态内部类被快速创建,如果你把它放在返回它的方法旁边,你也知道在哪里找到它(通常在原点附近)

【讨论】:

    【解决方案6】:

    我可能会自己走类路线,但根据您希望函数返回的内容,您可能能够通过返回某种值的容器而侥幸。

    【讨论】:

      【解决方案7】:

      这是我从另一个讨论中获得的一个可能的解决方案,并进行了一些改进。 它使用带有私有构造函数的公共内部类:

      public class Test {
          // Internal storage unit for the two values:
          // 'name' and 'age'.
          private Pair<String, Integer> info;
      
          public Test() {
              // Empty default constructor.
          }
      
          /**
           * The two values are stored in the Test class.
           *
           * @param name
           * @param age
           */
          public void setInfo(String name, int age) {
              info = new Pair<>(name, age);
          }
      
          /**
           * The 'name' and 'age' values are returned in a
           * single object.
           *
           * @return Both values in a Pair object.
           */
          public Pair<String, Integer> getInfo() {
              return info;
          }
      
          /**
           *  This is an Inner Class for providing pseudo 'tuplet'
           *  as a 'get' return value.
           *
           * @param <F> first internally stored value.
           * @param <S> second internally stored value.
           */
          public class Pair<F, S> {
      
              public final F first;
              public final S second;
      
              // This constructor is private to prevent
              // it being instantiated outside its
              // intended environment.
              private Pair(F first, S second) {
                  this.first = first;
                  this.second = second;
              }
      
              @Override
              public String toString(){
                  return first + ", " + second;
              }
          }
      
          /**
           * main method for testing of the class only.
           *
           * @param args
           */
          public static void main(String args[]) {
              Test test = new Test();
      
              test.setInfo("Peter Smith", 35);
              Test.Pair<String, Integer> pair = test.getInfo();
      
              System.out.println("name: " + pair.first);
              System.out.println("age: " + pair.second);
              System.out.println(pair.toString());
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2015-09-01
        • 2018-11-01
        • 2016-11-23
        • 1970-01-01
        • 2012-02-03
        • 2021-07-25
        • 1970-01-01
        • 1970-01-01
        • 2017-07-23
        相关资源
        最近更新 更多