Skip to main content
added 1169 characters in body
Source Link
h.j.k.
  • 1.8k
  • 1
  • 16
  • 20

It's also about communicating your intent of how the object should be used. For example, if your method expects a Map object with a predictable iteration order:

private Map<String, String> processOrderedMap(LinkedHashMap<String, String> input) {
    // ...
}

AndThen, if you absolutely need to tell callers of the above method that it too returns a Map object with a predictable iteration order, because there is such an expectation for some reason:

private LinkedHashMap<String,String> processOrderedMap(LinkedHashMap<String,String> input) {
    // ...
}

Of course, callers may still treat the return object as a Map as such, but that's beyond the scope of your method:

private Map<String, String> output = processOrderedMap(input);

Taking a step back

PersonallyThe general advice of coding to an interface is (generally) applicable, because usually it's the interface that provides the guarantee what the object should be able to perform, aka the contract. Many beginners start with HashMap<K, V> map = new HashMap<>() and they are advised to declare that as a Map, because a HashMap doesn't offer anything more than what a Map is supposed to do. From this, they will then be able to understand (hopefully) why their methods should take in a Map instead of a HashMap, and this lets them realize the inheritance feature in OOP.

To quote just one line from the Wikipedia entry of everyone's favorite principle related to this topic:

It is a semantic rather than merely syntactic relation because it intends to guarantee semantic interoperability of types in a hierarchy...

In other words, using a Map declaration isn't because it makes sense 'syntactically', but rather invocations on the object should only care that it is a type of Map.

Cleaner code

I find that this allows me to write cleaner code at times too, especially when it comes to unit testing. Creating a HashMap forwith a single test read-only test entry takes more than a line (excluding the use of double-brace initialization), when I can easily replace that with Collections.singletonMap().

It's also about communicating your intent of how the object should be used. For example, if your method expects a Map object with a predictable iteration order:

private Map<String, String> processOrderedMap(LinkedHashMap<String, String> input) {
    // ...
}

And if you absolutely need to tell callers of the above method that it too returns a Map object with a predictable iteration order, because there is such an expectation for some reason:

private LinkedHashMap<String,String> processOrderedMap(LinkedHashMap<String,String> input) {
    // ...
}

Of course, callers may still treat the return object as a Map as such, but that's beyond the scope of your method:

private Map<String, String> output = processOrderedMap(input);

Personally, I find that this allows me to write cleaner code at times too, especially when it comes to unit testing. Creating a HashMap for a single test read-only entry takes more than a line, when I can easily replace that with Collections.singletonMap().

It's about communicating your intent of how the object should be used. For example, if your method expects a Map object with a predictable iteration order:

private Map<String, String> processOrderedMap(LinkedHashMap<String, String> input) {
    // ...
}

Then, if you absolutely need to tell callers of the above method that it too returns a Map object with a predictable iteration order, because there is such an expectation for some reason:

private LinkedHashMap<String,String> processOrderedMap(LinkedHashMap<String,String> input) {
    // ...
}

Of course, callers may still treat the return object as a Map as such, but that's beyond the scope of your method:

private Map<String, String> output = processOrderedMap(input);

Taking a step back

The general advice of coding to an interface is (generally) applicable, because usually it's the interface that provides the guarantee what the object should be able to perform, aka the contract. Many beginners start with HashMap<K, V> map = new HashMap<>() and they are advised to declare that as a Map, because a HashMap doesn't offer anything more than what a Map is supposed to do. From this, they will then be able to understand (hopefully) why their methods should take in a Map instead of a HashMap, and this lets them realize the inheritance feature in OOP.

To quote just one line from the Wikipedia entry of everyone's favorite principle related to this topic:

It is a semantic rather than merely syntactic relation because it intends to guarantee semantic interoperability of types in a hierarchy...

In other words, using a Map declaration isn't because it makes sense 'syntactically', but rather invocations on the object should only care that it is a type of Map.

Cleaner code

I find that this allows me to write cleaner code at times too, especially when it comes to unit testing. Creating a HashMap with a single read-only test entry takes more than a line (excluding the use of double-brace initialization), when I can easily replace that with Collections.singletonMap().

Source Link
h.j.k.
  • 1.8k
  • 1
  • 16
  • 20

It's also about communicating your intent of how the object should be used. For example, if your method expects a Map object with a predictable iteration order:

private Map<String, String> processOrderedMap(LinkedHashMap<String, String> input) {
    // ...
}

And if you absolutely need to tell callers of the above method that it too returns a Map object with a predictable iteration order, because there is such an expectation for some reason:

private LinkedHashMap<String,String> processOrderedMap(LinkedHashMap<String,String> input) {
    // ...
}

Of course, callers may still treat the return object as a Map as such, but that's beyond the scope of your method:

private Map<String, String> output = processOrderedMap(input);

Personally, I find that this allows me to write cleaner code at times too, especially when it comes to unit testing. Creating a HashMap for a single test read-only entry takes more than a line, when I can easily replace that with Collections.singletonMap().