Read the javadoc: Map<K, V>.forEach() expects a BiConsumer<? super K,? super V> as argument, and the signature of the BiConsumer<T, U> abstract method is accept(T t, U u).
So you should pass it a lambda expression that takes two inputs as argument: the key and the value:
map.forEach((key, value) -> {
System.out.println("Key : " + key + " Value : " + value);
});
Your code would work if you called forEach() on the entry set of the map, not on the map itself:
map.entrySet().forEach(entry -> {
System.out.println("Key : " + entry.getKey() + " Value : " + entry.getValue());
});
Answer from JB Nizet on Stack OverflowVideos
Read the javadoc: Map<K, V>.forEach() expects a BiConsumer<? super K,? super V> as argument, and the signature of the BiConsumer<T, U> abstract method is accept(T t, U u).
So you should pass it a lambda expression that takes two inputs as argument: the key and the value:
map.forEach((key, value) -> {
System.out.println("Key : " + key + " Value : " + value);
});
Your code would work if you called forEach() on the entry set of the map, not on the map itself:
map.entrySet().forEach(entry -> {
System.out.println("Key : " + entry.getKey() + " Value : " + entry.getValue());
});
Maybe the best way to answer the questions like "which version is faster and which one shall I use?" is to look to the source code:
map.forEach() - from Map.java
default void forEach(BiConsumer<? super K, ? super V> action) {
Objects.requireNonNull(action);
for (Map.Entry<K, V> entry : entrySet()) {
K k;
V v;
try {
k = entry.getKey();
v = entry.getValue();
} catch(IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
action.accept(k, v);
}
}
javadoc
map.entrySet().forEach() - from Iterable.java
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
javadoc
This immediately reveals that map.forEach() is also using Map.Entry internally. So I would not expect any performance benefit in using map.forEach() over the map.entrySet().forEach(). So in your case the answer really depends on your personal taste :)
For the complete list of differences please refer to the provided javadoc links. Happy coding!
I know I'm a bit late for that one, but I'll share what I did too, in case it helps someone else :
HashMap<String, HashMap> selects = new HashMap<String, HashMap>();
for(Map.Entry<String, HashMap> entry : selects.entrySet()) {
String key = entry.getKey();
HashMap value = entry.getValue();
// do what you have to do here
// In your case, another loop.
}
Lambda Expression Java 8
In Java 1.8 (Java 8) this has become lot easier by using forEach method from Aggregate operations(Stream operations) that looks similar to iterators from Iterable Interface.
Just copy paste below statement to your code and rename the HashMap variable from hm to your HashMap variable to print out key-value pair.
HashMap<Integer,Integer> hm = new HashMap<Integer, Integer>();
/*
* Logic to put the Key,Value pair in your HashMap hm
*/
// Print the key value pair in one line.
hm.forEach((k,v) -> System.out.println("key: "+k+" value:"+v));
Here is an example where a Lambda Expression is used:
HashMap<Integer,Integer> hm = new HashMap<Integer, Integer>();
Random rand = new Random(47);
int i=0;
while(i<5){
i++;
int key = rand.nextInt(20);
int value = rand.nextInt(50);
System.out.println("Inserting key: "+key+" Value: "+value);
Integer imap =hm.put(key,value);
if( imap == null){
System.out.println("Inserted");
}
else{
System.out.println("Replaced with "+imap);
}
}
hm.forEach((k,v) -> System.out.println("key: "+k+" value:"+v));
Output:
Inserting key: 18 Value: 5
Inserted
Inserting key: 13 Value: 11
Inserted
Inserting key: 1 Value: 29
Inserted
Inserting key: 8 Value: 0
Inserted
Inserting key: 2 Value: 7
Inserted
key: 1 value:29
key: 18 value:5
key: 2 value:7
key: 8 value:0
key: 13 value:11
Also one can use Spliterator for the same.
Spliterator sit = hm.entrySet().spliterator();
UPDATE
Including documentation links to Oracle Docs. For more on Lambda go to this link and must read Aggregate Operations and for Spliterator go to this link.
If you want to modify the existing map, you don't need streams. Just loop and call removeIf():
sensor_tags.values().forEach(
m -> m.keySet().removeIf(datekey.getTime()::after));
I have made these two methods for you. The first creates a new hashmap and the second changes your Hashmap on the fly with the desired filtering. I didn't check for corner cases but they seem to work. Hope this helps:
Keeps your hashmap
private Map<String, Map<Date, String>> getFilteredResultsKeeping(Map<String, Map<Date, String>> sensor_tags,
Date givendate) {
return sensor_tags.entrySet().stream()
.map(sensorValue -> new SimpleEntry<>(sensorValue.getKey(),
sensorValue.getValue().entrySet().stream()
.filter(sensor -> !sensor.getKey().before(givendate))
.map(sensor -> sensor.getKey())
.collect(toMap(date -> date, date -> sensorValue.getValue().get(date)))))
.collect((toMap(SimpleEntry::getKey, SimpleEntry::getValue)));
}
Changes your hashmap
private Map<String, Map<Date, String>> getFilteredResultsRemoving(Map<String, Map<Date, String>> sensor_tags,
Date givendate) {
return sensor_tags.entrySet().stream()
.peek(sensorValue -> {
List<Date> invalidDates = sensorValue.getValue().entrySet().stream()
.map(sensor -> sensor.getKey())
.filter(date -> date.before(givendate)).collect(Collectors.toList());
invalidDates.forEach(date -> sensorValue.getValue().remove(date));
})
.collect((toMap(Entry::getKey, Entry::getValue)));
}