使用Java方式返回具有多个值的结果

Mik*_*dik 30 java

我习惯用Python开发,但出于工作原因必须用Java来实现.我正面临着一个在Python中无足轻重的任务,我想了解如何以正确的方式在Java中处理这个问题.

我需要解析持续时间字符串.它可以是毫秒(235毫秒)或秒(32秒).它也可以是"<1ms"作为特例.

解析在代码中至少发生三次,所以我想把它分成一个方法.但是我的代码确实需要知道,不仅仅是以ms为单位的结果值,还有它是ms还是s以及是否<1ms(0是不同的值).

在Python中,我只返回一个元组:

return (value_in_milliseconds,is_in_seconds,is_under_1ms)
Run Code Online (Sandbox Code Playgroud)

在CI中将定义这三个值的结构并返回它.在Pascal我定义了一条记录.

在Java中,我无法返回元组,我无法定义记录,所以我该怎么办?

我唯一能想到的是创建一个表示持续时间值的类.构造函数将获取字符串并解析它.该类将具有字段:int milliseconds,boolean inSeconds,boolean小于1ms.

但这听起来非常重量级 - 有更好的解决方案吗?

Eri*_*ikE 23

不要传递一组必须在它们之间保持一致的标志以形成合理的状态.如果is_in_secondsis_under_1ms两者都是true?为什么包含该单词的变量会milliseconds被解释为秒?代码中的错误外观.如果你可以对它做任何事情,错误的代码就不好 - 我们应该编写正确/错误的外观与现实相匹配的代码 - 应用于代码的最小惊讶原则,甚至可能是随后的成功之坑那些大脑会爆炸的开发者.

这听起来像是一些原始的痴迷代码气味/反模式,也许来自你的Python背景?(我对Python几乎一无所知,所以请随意忽略这个猜测.)

解决方案:创建一个真实的域级对象,表示大致持续时间的想法.

一种可能的实现方式:

  1. 创建一个DurationScale有成员枚举Second,Millisecond,SubMillisecond.

  2. 创建一个类ApproximateDuration,它接受duration整数和durationScale枚举值.

  3. 现在在您的其他代码中使用此对象.如果您需要对一系列这些持续时间求和,请创建一个知道如何解释每个持续时间并将它们添加到一起的类.或者为这个类添加方法.

一些概念的另一种像DurationScale可能是MarginOfError它可以在几毫秒内一些任意数量的,本身来表达.这可以允许您使用严格的数学公式来适当地增加误差范围,因为您将不同的ApproximateDuration对象一起合并为一个新ApproximateDuration对象.

注意:您可以看到有关我推荐此方法的原因的进一步讨论.

您确定的实现也是处理它的好方法,您可以在其中明确说明下限和上限:

public final class ApproximateDuration {
   private final int lowMilliseconds;
   private final int highMilliseconds;

   public ApproximateDuration(int lowMilliseconds, int highMilliseconds) {
      this.lowMilliseconds = lowMilliseconds;
      this.highMilliseconds = highMilliseconds;
   }

   public int getLowMilliseconds() {
      return lowMilliseconds;
   }

   public int getHighMilliseconds() {
      return highMilliseconds;
   }
}
Run Code Online (Sandbox Code Playgroud)

请注意,将单词Milliseconds放在变量和属性名称中很重要,这个类的不变性也是如此.

  • 这个答案与其他人的结合最终让我找到了正确的解决方案 - 结果完全不同,是的,更多的Java也是如此.我现在有一个持续时间类,我以毫秒为单位存储最小值和最大值,构造函数是一个解析器,另一个构造函数不带参数并生成0.它还有一个就地Add方法(取另一个相同类型的对象) ),所以它可以是一个累加器 - 我可以覆盖加法,但累加器看起来更有资源效率.最后它有一个返回布尔值的Compare方法.这是一个很好的旅程,谢谢大家! (2认同)

jiv*_*key 20

它与C结构没有什么不同,但你最终会以某种方式继承 Object

class Blah {
   public String value_in_milliseconds;
   public String is_in_seconds;
   public String is_under_1ms;
}
Run Code Online (Sandbox Code Playgroud)

  • 您可能不希望使用`String`类型 (4认同)
  • 是的,这是要走的路.在类中使它成为私有*静态*类.(请参阅*Effective Java*2e,第22项.)如有必要,package-private可以.它一定不公开. (2认同)

mas*_*ter 14

定义自己的类或使用例如apache commons:

return Triple.of(value_in_milliseconds, is_in_seconds, is_under_1ms);
Run Code Online (Sandbox Code Playgroud)

  • 我发现这是最实用的答案.Java有泛型 - 没有什么能阻止某人定义一些可以用于这种情况的Tuple类(具有不同数量的类型参数). (3认同)

Ros*_*han 8

我试着用下面的例子来传递一个代码Object[],保持简单:

public class MultiWayTest
{
    public static Object[] send() {
        return new Object[] { 1002322, false, true };
    }

    public static void main(String[] arg) {
        Object[] recieve=send();
    }
}
Run Code Online (Sandbox Code Playgroud)

你可能已经注意到了这个陈述 return new Object[] { 1002322, false, true };

希望有所帮助

  • 不是"基本上"一个数组,它**是一个数组.但你必须转换为适当的(对象)类型:`(整数)接收[0]`,`(布尔)接收[1]`(从那里自动拆箱可以转换为基元类型) (2认同)
  • 我赞成这个答案,因为阵列根本不是正确的解决方案.它需要原始值的装箱,编译器无法插入的强制转换,以及魔术数组索引 - 除非您将它们声明为常量,在这种情况下,您可以正确地执行它并创建数据类. (2认同)
  • @roshanmathew:我的意思是数字"0","1"和"2"在以下意义上都是"魔术数字".如果我想访问字段`isUnder1Ms`,我使用`arr [2]`.`2`和`isUnder1Ms`之间没有逻辑联系.换句话说,你不得不使用字段名,而是强制使用"名字"`0`,`1`和`2`.一个简单的拼写错误意味着你的代码做了错误的事情(比如说将2改为`1`)而不是编译(将`isUnder1Ms`改为`isUdner1Ms`,比如说). (2认同)

mer*_*ike 6

就个人而言,我会这样做:

class Duration {
    final int millis;
    final boolean specifiedInSeconds;
    final boolean under1ms;

    Duration(String s) {
        // parsing logic
    }
}
Run Code Online (Sandbox Code Playgroud)

这个解决方案相当短,允许编译器检测字段名称中的拼写错误,封装可能不会设置布尔值的不变量,并且可以安全地与其他代码共享,而不会有别名错误的风险.

  • 我认为meriton只是意味着构造函数设置了布尔值,然后没有其他人可以错误地设置它们. (3认同)