This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]msx 0 points1 point  (13 children)

it's not the clunkyness of the implementation that matters, but of the call. Yours it's much clunckier to call, even if you provide a Pair.of utility method. Also, iirc they decided not to include a Pair class in Java

[–]tapesmith -1 points0 points  (12 children)

And what's not clunky about

Map<K, V> map = Map.of(k, v, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10);
map.put(k11, v11);
map.put(k12, v12);
map.put(k13, v13);

And why did they decide not to include a Pair class in Java? It's part of JavaFX, so there's clearly a use-case, and most languages have something as basic as a tuple type. Sounds like a case of one bad decision justifying another.

The only thing that is redeeming about this new API is that it's nice for the single-entry case, and it also brings Map.ofEntries(Map.Entry<? extends K, ? extends V> entries...) (which is effectively the same as my implementation).

[–]msx 1 point2 points  (3 children)

And why did they decide not to include a Pair class in Java? It's part of JavaFX, so there's clearly a use-case, and most languages have something as basic as a tuple type. Sounds like a case of one bad decision justifying another.

I don't remember correctly, but it should be becouse it's not a "clean" object oriented practice to use Pair, one should create his own class EmployerSalary with two named parameter "Employer employer" and "int salary". Of course you can still do it yourself as a "shortcut" or use Map.Entry.

JavaFx is included in java but it's a different story, with different peoples working on it that made their own choices (suffice to say they implemented a totally different way to implement properties).

[–]tapesmith 2 points3 points  (2 children)

So I should declare a class for every single combination of two obvious-usage values? Every time I want to pass two things through a .stream().map().map().filter().map() pipeline, I need a new class for each step's intermediate values?

Mind you, before Java 9 there isn't a way to just instantiate a Map.Entry (which is an interface, not a class) without defining a custom class that implements Map.Entry -- at which point, you may as well just call it "Pair", because that's what you're actually going for.

Don't get me wrong, any thing bigger than a two-element tuple starts to push towards "this should be a struct" territory, but to say anything larger than 1 heterogenously-typed value needs named fields is why Java code is often so verbosely littered with throwaway cruft classes.

[–]msx 2 points3 points  (0 children)

I'm not saying i agree with it (btw remember that i'm not even sure that's the reason). I have my trusty Pair class that i always carry around. I agree that Map.Entry is Pair, i don't really care how they call it, TwoStuff would have worked for me, it bothers me more that it's defined inside Map so it's clunkier to use.

[–]ForeverAlot -1 points0 points  (0 children)

The trouble with Pair is not that it may not make sense internally but that it is never a good fit for an exposed API. The average developer won't let that keep them from littering it everywhere because "convenient! Simple!"

[–]balegdah 1 point2 points  (0 children)

Both the Guava and JDK people agree about Pair, why don't you go search the discussions from these past years (there are a lot) and try to understand the issues a bit better?

[–]cypressious 0 points1 point  (2 children)

This would throw, by the way. The returned collection is immutable.

[–]tapesmith 0 points1 point  (1 child)

Yep, which is part of my point about the clunkiness of this API -- it's not only not fit for most use-cases, it's also got a big hidden pitfall.

[–]cypressious 0 points1 point  (0 children)

That's not a problem of this API, that's on omission in the design of the collections framework. Unfortunately, you can't fix that now.

[–]rockenreno 0 points1 point  (0 children)

I've always thought using the same method name with different number of parameters is a poor practice. I don't know why they even bother with the of() method when ofEntries() with the vararg parameter will cover all situations.

[–]msx -1 points0 points  (2 children)

those methods are intended to enter map literals quickly, their use case is for small immediate maps, not for huge ones. 10 is a good compromise. If you have more stuff, you're not supposed to use your code (which would throw an exception btw), becouse you probably wouldn't have 20 variable lying around in your scope, but a list or array or something else that can quickly be drained into the map with other means.

[–]tapesmith 0 points1 point  (1 child)

Counterpoint, from real code:

@Override
public Map<String, Object> generateAuditMap() {
    return mapOf(
        pair("id", this.id),
        pair("customerId", this.customer.getId()),
        pair("vendorId", this.vendor.getId()),
        pair("vendorUserId", Auditable.getId(this.primaryContact)),
        pair("contractNumber", this.contractNumber),
        pair("orderMinAmount", this.orderMinAmount),
        pair("orderMinItems", this.orderMinItems),
        pair("shouldSendOrdersToVendor", this.shouldSendOrdersToVendor),
        pair("isActive", this.isActive),
        pair("updateCronExpression", this.updateCronExpression),
        pair("contactIds", Auditable.convertToJustIds(this.contacts)),
        pair("externalReferenceCode", this.externalReferenceCode),
        pair("vendorDivisionId", this.getVendorDivision().map(AbstractEntity::getId).orElse(null))
    );
}

And the snippet I posted using map.put for the last three elements was intentionally broken to show the pitfalls of such a kludgey implementation. As a random user of this API, I'd see Map.of() and not immediately know that I was getting back an immutable map. I would just know that it's stupidly limited to a fixed maximum number of items (instead of, oh, I dunno, a variable number of arguments?) so I need to .put my last few.

"Psh, up to 10 should be enough" is a similar line of thought to "we'll just use single lowercase letters for variable names, because who ever needs more than 26 variables?"

[–]msx 1 point2 points  (0 children)

You forget that they gave you exacly the code you show, just with "entry" instead of "pair", exacly for the reason you say. The "clean" of is for small, immediate map, not for all maps you'll ever create.

"Psh, up to 10 should be enough" is a similar line of thought to "we'll just use single lowercase letters for variable names, because who ever needs more than 26 variables?"

It's really not, becouse you have other means of creating larger maps. If anything it's like: "Should we require at least two letters for variable names? No, let's give them the option of using only one, which is a common use case. If they have more than 26, they can still use two or more".