在 Java 中返回多个值的最佳实践?
Posted
技术标签:
【中文标题】在 Java 中返回多个值的最佳实践?【英文标题】:Best practice for returning multiple values in 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。 新类记录语义,编译时检查返回值。为了可维护性,值得花时间。 懒惰可以提高效率:) 三年后才有同样的感受。我落后了多少:( 【参考方案1】:不,这种结构在 Java 中不存在,但您可以查看JavaTuples library,它可能适合您的需求并提供非常优雅的解决方案。使用Triplet<Boolean, String, Boolean>
【讨论】:
但是通过一个小类,您可以使用 getter 访问成员,或者使值可选。 写return new Triplet<Boolean, String, Boolean>(actual values)
也不是优雅的光辉典范:)
这其实是个相当热门的话题:***.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 --> 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());
【讨论】:
以上是关于在 Java 中返回多个值的最佳实践?的主要内容,如果未能解决你的问题,请参考以下文章
【翻译】Prometheus最佳实践 Summary和Histogram