Actually you print the TreeSet<Double> set
and this misleads you into thinking that your collection is populated. Because your error is not on set
but rather on TreeMultimap<String,Double> mmap
: you execute Ordering.natural().min(mmap)
and that's where the issue is coming from. Guava specifies that looking for the min (or max) element in an empty collection will result in throwing a NoSuchElementException
, which is what you have here.
Iterable throws NoSuchElementException even after I have verified by printing each element
-
10-06-2023 - |
题
I have a bunch of Map<Integer, TreeSet<Double>>
objects, and I am passing the values off to another method. I got a NoSuchElementException
in that method, so started debugging, and saw that the call to Map#values()
throws this exception. But, when I loop through the values, it prints all the values perfectly. Here's the code snippet that's causing this issue:
Map<Integer, TreeMultimap<String, Double>> kMap = Maps.newTreeMap();
for (int i = 0; i < 3; i++) {
TreeMultimap<String, Double> treeMultimap = TreeMultimap.create();
treeMultimap.putAll("a" + i, Lists.newArrayList(0.0, 0.06, 0.17, 0.23));
treeMultimap.putAll("b" + i, Lists.newArrayList(0.0, 0.16, 0.34, 0.49));
kMap.put(i, treeMultimap);
}
Map<Integer, TreeSet<Double>> rescaledKMap =
Maps.transformEntries(kMap, ToRescaledValueMap(1.2));
Iterable<TreeSet<Double>> treeSets = rescaledKMap.values();
// Prints out each element correctly. No exception is thrown.
for (TreeSet<Double> set : treeSets)
System.out.println(Joiner.on(',').join(set));
// NoSuchElementException thrown in getMeanPlot() before anything happens there.
TreeMap<Double, Double> mean_rescaledKMap =
getMeanPlot(rescaledKMap.values());
The signature is getMeanPlot(Iterable<TreeSet<Double>>)
.
How is the iterable correct just before it gets passed to the second method, but throws an exception just as the second method start?
Stack Trace
The stack trace shows the Maps.EntryTransformer
object ToRescaledValueMap
as the culprit. Here's the trace:
Exception in thread "main" java.util.NoSuchElementException
at java.util.TreeMap$PrivateEntryIterator.nextEntry(TreeMap.java:1113)
at java.util.TreeMap$EntryIterator.next(TreeMap.java:1151)
at java.util.TreeMap$EntryIterator.next(TreeMap.java:1146)
at com.google.common.collect.AbstractMapBasedMultimap$Itr.next(AbstractMapBasedMultimap.java:1145)
at com.google.common.collect.Ordering.min(Ordering.java:460)
at com.google.common.collect.Ordering.min(Ordering.java:479)
at DistributionMetricExperiment$6.transformEntry
Does this have anything to with Guava's lazy initialization? I can write my own little method instead of using the Maps#transformEntries
method, but not knowing the reason behind this bug is ... well ... bugging me. The entry transformation is as follows:
static Maps.EntryTransformer<Integer, TreeMultimap<String,Double>, TreeSet<Double>>
ToRescaledValueMap(final double interval_length) {
return new Maps.EntryTransformer<Integer, TreeMultimap<String,Double>, TreeSet<Double>>()
{
public TreeSet<Double> transformEntry(Integer i, TreeMultimap<String,Double> mmap) {
double mmap_min = Ordering.natural().min(mmap.values());
double mmap_max = Ordering.natural().max(mmap.values());
TreeSet<Double> rescaledValues = Sets.newTreeSet();
for (double val : mmap.values())
rescaledValues.add(interval_length * (val - mmap_min)/(mmap_max - mmap_min));
return rescaledValues;
}
};
}
Edit:
- I don't know whether this matters or not, but wanted to add that I have also issued the same print statements (the for loop over
Iterable<TreeSet<Double>
in the above code) as the first statement ofgetMeanPlot
. Even there, it prints alright, and then throws the exception. - My apologies for the use of underscore in variable names. The variables are reflecting subscripts I have been using in the maths behind my code. I am aware of the naming convention, but in this code I was more focused on having the ability to recognize the mathematical meaning of a variable just by looking at it.
解决方案