Returning a result with several values the Java way

Mikhail Ramendik :

I am used to developing in Python, but for work reasons have to do it in Java. I am facing a task that would be trivial in Python, and I'd like some advice on how to handle this in Java the proper way.

I need to parse a duration string. It can be in milliseconds (235ms) or seconds (32s). And it can also be "< 1ms" as a special case.

The parsing happens at least three times in the code so I'd like to separate it into a method. But my code does need to know, not just the resulting value in ms, but also whether it was in ms or s and whether it was <1ms (0 is a different value).

In Python I would just return a tuple:

return (value_in_milliseconds,is_in_seconds,is_under_1ms)

In C I would define a struct of these three values and return it. In Pascal I'd define a record.

In Java I can't return a tuple and I can't define a record so what do I do?

The only thing I can think of is creating a class representing a duration value. The constructor would take the string and parse it. The class would have fields: int milliseconds, boolean inSeconds, boolean under 1ms .

But this sounds terribly heavyweight - is there a better solution?

ErikE :

Don't pass around a set of flags that must be consistent between them to make a sensible state. What if is_in_seconds and is_under_1ms are both true? And why would a variable that contains the word milliseconds ever be interpreted as seconds? How wrong-looking that will be in the code. Wrong-looking code is not good if you can do anything about it--we're supposed to write code whose appearance of rightness/wrongness matches reality—the Principle of Least Astonishment applied to code, and perhaps even the Pit of Success for subsequent developers whose brains will explode on that.

This sounds like maybe a bit of the Primitive Obsession code smell/antipattern, perhaps from your Python background? (I know next to nothing about Python so feel free to disregard this guess.)

Solution: make a real domain-level object that represents the idea of an approximate duration.

One possible implementation of that:

  1. Create a DurationScale enum that has members Second, Millisecond, SubMillisecond.

  2. Create a class ApproximateDuration, that takes a duration integer and a durationScale enum value.

  3. Now consume this object in your other code. If you need to sum a series of these durations, make a class that knows how to interpret each one and add them together. Or add methods to this class.

An alternative to some concept like DurationScale could be MarginOfError which can be expressed in some arbitrary number of milliseconds, itself. This could allow you to use a strict mathematical formula to increase the margin of error appropriately as you sum different ApproximateDuration objects together into a new ApproximateDuration object.

Note: You can see some further discussion on why I recommend this approach.

The implementation you settled on is also a good way to handle it, where you explicitly state the lower and upper bounds:

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

Note that putting the word Milliseconds in the variables and property names is important, as is the immutability of this class.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=426591&siteId=1