2

How do I get rid of magic numbers in java without declaring a massive amount of finals or static finals? Keep in mind looping, arrays are not allowed. It doesn't seem possible? Help appreciated. thanks.

Example code:

drawOval(5, 5, width, height);
drawOval(10, 10, width, height);
drawOval(15, 15, width, height);
drawOval(20, 20, width, height);
drawOval(25, 25, width, height);
JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
Larry21
  • 169
  • 3
  • 7
  • It depends on what meaning the values have to each and if they can change dynamically through out the runtime of the application – MadProgrammer Oct 07 '13 at 02:31
  • "Looping not allowed?" I mean if you're handicapping us from using the best solution... – roippi Oct 07 '13 at 02:35
  • There's not really a good way -- in Java or most languages. One thing I've taken to doing (in Objective-C) is encoding sequences of "magic numbers" in a JSON literal that will be interpreted at runtime. But there is substantial overhead to this, which is OK in some cases and not others. – Hot Licks Oct 07 '13 at 02:37
  • @roippi I think the op means that he doesn't want the values 5,10,15 etc to be generated by a loop such as `for(int i=5;i<=25;i+=5)` – vandale Oct 07 '13 at 02:37
  • One important thing to do is to comment things adequately, so that the derivation of the numbers is clear. Using constants does no good (in fact, negative good) if the reason for those constant values is not clear. – Hot Licks Oct 07 '13 at 02:39
  • 1
    Why are looping and arrays disallowed? A loop is the correct solution here. Stack Overflow is about getting a solution to your problem, not about playing silly games with what the solution is and isn't allowed to be. – Dawood ibn Kareem Oct 07 '13 at 02:44
  • @vandale I'm aware of what he meant, and that restriction is still silly. If you want you can declare two BOUNDARY constants and one STEP constant, and loop over those. It more declarative of the design intent ("I am creating a series of equally-sized uniformly-spaced ovals") than just making a boatload of constants and expecting someone to _see_ the pattern, obvious though it may be. – roippi Oct 07 '13 at 02:44

4 Answers4

7

Defining constants is really your only option. What's your opposition to using them? They are definitely worth their space in this context. Future developers would much rather see extra constants than be confused by what those numbers mean.

Oleksi
  • 12,947
  • 4
  • 56
  • 80
  • 2
    +1. Please use well-named constants. It makes everyone else's job infinitely easier. – asteri Oct 07 '13 at 02:31
  • 1
    Yes, and assuming the shapes' locations are correlated, I would use *one* well-named constant and `*2`, `*3`, etc for the rest. – lc. Oct 07 '13 at 02:38
4

The direct answer is that named constants is the only way to avoid having magic numbers in your code.


But the flip-side is that it is debatable whether magic numbers are harmful or the extent that they are harmful. And in this particular case it is debatable whether these actually qualify as "magic" numbers ... at least, IMO.

Lets illustrate this:

// Alternative #1

private final int PLACE_1_X = 5;
private final int PLACE_1_Y = 5;
...
drawOval(PLACE_1_X, PLACE_1_Y, width, height);

// Alternative #2
drawOval(5, 5, width, height);

Which of these is actually more readable? Does defining named constants (which are most likely at a different point in the source code!) make it easier to understand what is going on? Don't you now have the problem that you have to look in two places not one to understand what a specific drawOval call is going to draw?


The bottom line is that the "no magic numbers" dogma only really applies when the meaning of the numbers is not self-evident from the context ... or when the number is actually a repeatedly used constant. (Like if we were going to use PLACE_1 lots of times in the same "picture".)

You need to think about the context, not just blindly apply the dogma.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Very true. The problem is that the non-dogmatic case-by-case approach is very hard to implement in static code analysis rule :) – Frettman Jan 06 '23 at 12:30
1

An alternative to finals / static that I've already seen is to use a custom object as an argument:

public void drawOval(OvalArg arg) {
    // ...
}

OvalArg arg = new OvalArg();
arg.first = 10;
arg.second = 10;
arg.width = 100;
arg.height = 500;

drawOval(arg);

However, this approach implies that you cannot see directly which arguments must be sent to a method (unless you look into the argument object), and requires extra validation to ensure that your custom object is correctly filled. For that reason, I would recommend using constants.

Frederik.L
  • 5,522
  • 2
  • 29
  • 41
  • 1
    If you've ever used `GridBagConstraints` with Swing, you know just how ridiculously annoying this technique is. Haha – asteri Oct 07 '13 at 02:37
  • Haha, I never been a great fan of `GridBagConstraints`, it looked kind a "hard coded" UI to me. I saw it at school, but prefered more dynamic layouts as well. – Frederik.L Oct 07 '13 at 02:40
0

Adding to the other answers we can also use Enums to declare constants and they can have values attached like width and height.

public enum Dimensions {
  
  DIMENSION_FIVE_FIVE(5, 5);

  private final int height;
  private final int weight;

  private Dimensions(int height, int width) {
     this.height = height;
     this.weight = weight;
  }

}

Please ignore my naming convention, suggestions are welcome.

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Sahil13399
  • 41
  • 3