2

I have hashmap like below

HashMap<String, String> attributes= new HashMap<String, String>();

I am trying to add values in it like below

attributes.put("Id", systemGeneratedDetails.get(0).getId());
attributes.put("Name", systemGeneratedDetails.get(0).getName());

but sometimes getId or getName will return null or blank. In that case I don't want to add it in map.

How to do it in Java?

khelwood
  • 55,782
  • 14
  • 81
  • 108
Johny
  • 49
  • 6

2 Answers2

3

The simplest way to do this would be to wrap the logic within an if-statement:


var details = systemGeneratedDetails.get(0);
var id = details.getId();
var name = details.getName();

if (id != null && !id.isBlank()) {
  attributes.put("Id", id);
}
if (name != null && !name.isBlank()) {
  attributes.put("Name", systemGeneratedDetails.get(0).getName());
}

Another interesting method of going about this is to use Optionals:

var details = Optional.of(systemGeneratedDetails.get(0));
var idOpt = details.map(YourDetailType::getId).filter(s -> !s.isBlank());
var nameOpt = details.map(YourDetailType::getName).filter(s -> !s.isBlank());

idOpt.ifPresent(id -> attributes.put("Id", id));
nameOpt.ifPresent(name -> attributes.put("Name", name));

Just make sure to replace YourDetailType with the actual type of systemGeneratedDetails.get(0).

Please keep in mind however, that this will create a bunch of extra objects (though the impact should be minimal thanks to JVM escape analysis), and that some programmers frown upon the practice of using Optionals as anything except for return values.

Jeroen Steenbeeke
  • 3,884
  • 5
  • 17
  • 26
  • `Optional` wasn't designed to be used for validation, see the answer by *Stuart Marks* (Java and OpenJDK developer) : ["A typical code smell is, instead of the code using method chaining to handle an Optional returned from some method, it creates an Optional from something that's nullable, in order to chain methods and avoid conditionals."](https://stackoverflow.com/a/34458582/17949945). The only purpose of Optinal is to serve as a return type. – Alexander Ivanchenko Sep 23 '22 at 09:20
  • You're making an [appeal to authority](https://en.wikipedia.org/wiki/Argument_from_authority) to advocate a limitation on the use of Optional that runs contrary to how it's actually used at many companies. By this logic I could simply extract methods for my first three statements and then it would be fine while making the code less readable. – Jeroen Steenbeeke Sep 23 '22 at 09:34
  • Optional was introduced as a part of the Java specification request dedicated to the lambda expressions, and the information I referred to isn't an opinion of a single individual, but it reflects the result of the work that an expert group done over the years. Therefore, you can't claim that it has no value. – Alexander Ivanchenko Sep 23 '22 at 11:30
  • And if you're interested in classifying logical fallacies, then you have to agree that the phrase *"used at many companies"* is subjective. It doesn't prove the **correctness** of such practice. And it's difficult to evaluate whether it's wide-spread, and your conclusion that such style of writing code in based on your personal experience. But if we imagine that there were some data that *`"90% of Java-developers do so"`* that would be an *argumentum ad populum* which still luck the proof of correctness. – Alexander Ivanchenko Sep 23 '22 at 11:31
  • *"I could simply extract methods for my first three statements and then it would be fine while making the code less readable"* - sorry, which statements? And how extracting the logic into a method and documenting it (at least by giving it a name) decreases the readability? – Alexander Ivanchenko Sep 23 '22 at 11:33
  • Over-segmentation of methods (i.e. blindly going full Uncle Bob) decreases the readability of methods because it is no longer clear at a glance what's going on ([great presentation on the subject](https://vimeo.com/49484333)). Also I later realized that if I extract all three statements to methods then I would be passing the Optional as a parameter so that's not going to fly. As for correctness: I favor pragmatism over correctness. As long as the downsides of doing things a certain way (in this case: creating a bunch of extra objects) are known and acceptable, it is not a problem – Jeroen Steenbeeke Sep 23 '22 at 12:03
0

putIfAbsent() + replace()

You can use a combination Map.putIfAbsent() + three-args version of Map.replace():

attributes.putIfAbsent("id", systemGeneratedDetails.get(0).getId());
attributes.replace("id", "", systemGeneratedDetails.get(0).getId());

To avoid code-repetition, this logic can be extracted into a separate method and gentrified:

public static <K, V> void putIfNullOrEmpty(Map<K, V> map,
                                           K key, V oldValue, V newValue) {

    map.putIfAbsent(key, newValue);
    map.replace(key, oldValue, newValue);
}

Usage example:

putIfNullOrEmpty(attributes, "id", "", systemGeneratedDetails.get(0).getId());
putIfNullOrEmpty(attributes, "Name", "", systemGeneratedDetails.get(0).getId());

compute()

Another way to achieve that is by using Java 8 method Map.compute(), which expects a key and a remappingFunction responsible for generating the resulting value based on the key and existing value associated with the key:

attributes.compute("Id", (k, v) -> v == null || v.isEmpty() ? 
                         systemGeneratedDetails.get(0).getId() : v);

To avoid redundancy, you can extract this logic into a separate method and gentrify it:

public static <K, V> void putIf(Map<K, V> map,
                                Predicate<V> condition,
                                K key, V newValue) {
    
    map.compute(key, (k, v) -> condition.test(v) ? newValue : v);
}

Usage example:

Predicate<String> isNullOrEmpty = v -> v == null || v.isEmpty();
        
putIf(attributes, isNullOrEmpty, "id", systemGeneratedDetails.get(0).getId());
putIf(attributes, isNullOrEmpty, "Name", systemGeneratedDetails.get(0).getId());
Alexander Ivanchenko
  • 25,667
  • 5
  • 22
  • 46