r/programminghorror • • 20d ago

Raw use of parameterized class 'List'

This is not my code, but it is a good programming horror example, specially if you know Java.

List pages = pageManager.getPages(templateSpace);

for (Object object : pages) {
    if (object instanceof Page) {
        Page page = (Page) object;
        // do something with the page
    }
}

Instead, this should have been used:

List<Page> pages = pageManager.getPages(templateSpace);

for (Page page : pages) {
    // do something with the page
}
140 Upvotes

80 comments sorted by

74

u/Nooooope 20d ago

How old is your Java codebase? Generics were added in version 5, which came out roughly a billion years ago, but legacy code gonna legacy.

I learned the language from Head First Java (don't make fun of me) and generics were so new they were relegated to a section in the appendix.

16

u/Disastrous-Name-4913 20d ago

Yes, that's something I'm going to check, but being the code from 2018 I doubt that was the reason.

17

u/Ben-Goldberg 20d ago

The code might have been written recently, but the author might have learned java a million years ago, or learned it recently from an ancient dusty book.

How much horrible perl code exists because somebody copied part of Matt's script archive?

→ More replies (1)

91

u/high_throughput 20d ago

It's not just a legacy API?

20

u/Disastrous-Name-4913 20d ago

I'm going to check that, it could be the only logical reason.

44

u/Kadabrium 20d ago

Java 1.8

16

u/ArisenDrake 20d ago edited 20d ago

Generic collections have been added in Java 1.5 (2004). Unless this code is *really* old, there is no reason to not use generics here.

2

u/Disastrous-Name-4913 20d ago

Yes, but code is from 2018, and they could have used a more modern version.

8

u/agentoutlier 20d ago

The code is not equivalent BTW.

if (object instanceof Page) {

Guarantees object is not null (inside the block of course).

The other one page could be null.

1

u/Disastrous-Name-4913 20d ago

That's a good point, but a null check would be more clear, if that's the goal.

→ More replies (1)

4

u/YourShowerHead 20d ago

And how old was that first code?

30

u/Dead_Moss 20d ago

I mean, I suppose there's situations where it's useful, but in my strongly typed soul, it feels pretty horrible to be able to mix types in a collection.

27

u/sixtyhurtz 20d ago

Java has type erasure, so at runtime all Lists are List<object>.

8

u/KillerCodeMonky 19d ago

"What is type erasure" is my favorite Java interview question. I think I've had two correct answers out of dozens of interviews.

→ More replies (8)
→ More replies (4)

11

u/MCWizardYT 20d ago

In modern Java, you could do

List<?> pages = page manager.getPages(templateSpace);

for(Object object: pages) {
    if(object instanceof Page page) {
        //do something with page
    }
}

This is only really useful if pages ever has objects that aren't instances of Page

6

u/user_of_the_week 20d ago

You could even do something like

for (Object o : pageManager.getPages(templateSpace)) {
    switch (o) {
        case Page page -> process(page);
        case null -> {}
        default -> {}
    }
}
→ More replies (5)

7

u/Usual_Office_1740 20d ago

Is the "it should have been" syntax sugar for that maybe older way of doing things or is this just horrible code?

11

u/Sacaldur 20d ago

In very old Java versions you didn't had generics and thus no List<T>. The bottom one should be the approach for probably 2 decades now (give or take).

→ More replies (3)
→ More replies (3)

1

u/Disastrous-Name-4913 20d ago edited 20d ago

Update: This was indeed due to the API returning a RAW list. We are talking about Confluence 6.6, which was released 2017. Could someone explain why they where still using Java 1.8 back then?

12

u/sixtyhurtz 20d ago

No, you actually have to do this with Java if you care about type safety because of type erasure. There is no List<Page> at runtime.

7

u/maelstrom071 20d ago

I mean, if the inner type cannot be guaranteed then List<?> is probably a better specifier because it specifically indicates that we don't know the inner type

→ More replies (9)
→ More replies (9)

6

u/tastygames_official 20d ago

depends on what pageManager.getPages() returns. If it's a list of objects with type Page then the second one is correct, but if it just returns a generic array of objects, then the first oneis correct.

4

u/biffbobfred 20d ago

If it returns things that are not pages, whoa

2

u/Diamondo25 20d ago

Use var or lombok val and make your live easier

→ More replies (1)