17

Came across this coding standard from Oracle:

Do not use a static array of strings.

What is the reason for this recommendation?

13
  • 1
    A few of these tips are there mainly for readability purposes. I guess maybe the idea is that you would use an enum with String values or something along those lines instead? Commented Aug 15, 2016 at 17:17
  • 1
    The reason might just be valid in the context of the Oracle retail applications this document refers to but it might be to counter bad style like overuse of static variables (and strings might be the most common case). Commented Aug 15, 2016 at 17:18
  • 2
    A lot of the recommendations in this document are quite questionable nowadays. The most obvious being "Do not concatenate strings. Use StringBuilder instead." Commented Aug 15, 2016 at 17:21
  • 3
    @Cricket I think the reason could be this predates 1.5 (which is when enums were added, I believe). Commented Aug 15, 2016 at 17:26
  • 2
    @VinceEmigh That might have been the intended context. But I find this interpretation a bit stretched. Who would concatenate a constant string in a loop over and over again? Commented Aug 15, 2016 at 17:39

4 Answers 4

3

Arrays are mutable containers. Global mutable container without built-in synchronisation is multi-threaded horror waiting to happen. You can store reference to that array in some local context and then have it's content changed at any time without you knowing it. Or vice versa you may assume that this is convenient global state, but then every client must know the exact correct way to synchronise its access to that state. And somebody will forget and bug will be born.

Sign up to request clarification or add additional context in comments.

8 Comments

But why Strings in particular?
Truth be told: no idea. IMO this should be relevant to arrays of any class.
@DiegoMartinoia, I would guess Strings are called out in particular due to the statement two lines above, "Oracle Retail products tend to be string-intensive". Most likely, Oracle had some specific issues with developers using String arrays in the past.
This doesn't sound right. As others have mentioned, this applies to all types. But what makes me lean further towards disagreement is that memory barriers could be used to prevent concurrency issues, as one should do with any type in this situation.
The problem with memory barriers in this case is that EVERY client of that arrays must know the right way to use them (on which monitor to synchronise) and remember to do it every single time. This is bad.
|
2

I believe it's due to developers using String as a replacement (most likely unintentionally) for enumeration, and the static String[] was a way to group these types.


It could be targetting design flaws that were common at the time the article was written

For all we know, this article could be targetting the Java 4- code base.

Not saying this was written during Java 4, but that most production code existing at the time may have been written in Java 4. The lack of autoboxing pitfalls (which are quite common) and no mentions of generics (raw types) lead me to believe this.

Why would Oracle enforce such a cryptic principle?

I don't believe it has to do with global state, since I'm sure singletons would have been mentioned (being the pinnicle of global state).

I doubt concurrency is the issue, since the article does not mention anything else about sharing data across threads, or even using multiple threads. You would assume they would have mentioned SOMETHING about the thread environment.

Misusing String for type enumeration purposes was common back in the day, so I'm sure this statement (if related to what I think it is) was a lot easier to understand back then. I find it to be quite a stretch that this statement was just as cryptic back then, yet no one has cared to question it, resulting in the lack of google results when digging into this.

My Answer

Developers to this day still misuse String for type information. With the lack of enumeration, I could see how a developer may be tempted to do something along the lines of:

class Card {
    static String HEARTS = "HEARTS";
    static String DIAMONDS = "DIAMONDS";
    static String CLUBS = "CLUBS";
    static String SPADES = "SPADES";

    static String[] CARD_TYPE = {
        HEARTS, DIAMONDS, CLUBS, SPADES
    };

    private String type;
    //...
}

Using the array for easy looping (as one would do with Enum.values()).

Using String as enums is frowned upon:

  1. It's not type safe. If MAGE can be passed to a method, ANY String could be passed in it's place. This leads us to...

  2. Mistakes are easier to make. It's possible for a typo to go unnoticed, which may seem small for the average developer, but could be catastrophic for businesses with large code bases and many consumers (such as Oracle). For example: a hidden typo results in a comparison returning false. This prevents a service from launching. The lack of this service results in a bug. If not found before users notice the bug, it could lead to exploits.

This could be fix by using Java's built-in type system:

abstract class CardType {

}

class Hearts extends CardType {

}

....

Or

enum CardType { HEARTS, DIAMONDS, ...; }

Not only is this less error-prone, but it allows you to use polymorphism, which prevents the need to check the value in order to trigger a specific behavior. The behavior can be contained in the type itself.


Although I can't promise this is the correct answer, it seems to be the only answer that does not depend on the use of modifiers that weren't mentioned in the statement.

Yes, the example above does not use proper constants (lacks the final). But although constants should be preferred, they are not required to benefit from this design (being able to use String for type information) nor does the design require it to work . Since people may not have always used constants for this, they could have left out the final or "array of constants" for this purpose.

1 Comment

You make an excellent point on enumeration and I think you're right about this being based on Java 4. At least one of the Oracle POS frameworks (Tour) does seem to use Strings to hold state (among other things).
1

This way undermines the object oriented paradigm. Moreover it's a security hole, because the final keyword assures only reference value and leaves the content to be changed easily.

2 Comments

That's true for every final Object.
Also it says static arrays, not final arrays, no?
1

Some of them are arbitrary. For example, having a single return statement is a matter of style (maybe related to some analysis tool that in the past couldn't handle multiple return paths?).

Some of them are outdated. Like the one about StringBuilding.

I'd assume that these are a mixture of old performance recommendations and style guides. I'd reckon the String static array one falls in the latter category, with maybe a hint towards what others have said about the possible link with the introduction of enums (maybe that's why Strings in particular).

Some of them are actually completely unfeasible when you try to apply them to modern frameworks: "Do not use a switch to make a call based on the object type.", for example, is at the core of Akka Java (onReceive) method and in general in any type of pattern matching in Java...

While I admit it's curious, I'd say it's probably something related to some specific tool they used in the past or to the enum possibility mentioned. But it's just my opinion, not a definitive answer.

10 Comments

Doesn't switching on object type negate polymorphism?
@ZachTeater Not really. Say you have interface A implemented by B and C (strategy pattern-ish). You have a collection of B and C types (maybe your requests to be handled), so you do List<A> . Then you can process them by (for a:listA -> case B -> processB(a) caseC -> processC(a)) or something similar. It's convenient, and it uses polymorphism.
@ZackTeater another example is Akka as mentioned. Your receive method (in Java) will be all if (msg instanceof X).. elseif (msg instanceof Y)...
wouldn't polymorphism be for A to have a method called process(), which is implemented differently by B and C. Then you could do ... for a:listA --> process(a).
Also, isn't using instanceOf the anti-pattern for polymorphism?
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.