下面列出了java.util.SortedMap#putAll ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
public SortedMap<String, T> getResults(final Comparator<Entry> comparator) {
SortedMap<String, T> sm = new TreeMap<String, T>(new Comparator<String>() {
public int compare(String o1, String o2) {
T t1 = map.get(o1);
T t2 = map.get(o2);
int delta = comparator.compare(t1, t2);
if (delta == 0) {
delta = o1.compareTo(o2);
}
return delta;
}
});
sm.putAll(map);
return sm;
}
public SortedMap<String, T> getResults(final Comparator<Entry> comparator) {
SortedMap<String, T> sm = new TreeMap<String, T>(new Comparator<String>() {
public int compare(String o1, String o2) {
T t1 = map.get(o1);
T t2 = map.get(o2);
int delta = comparator.compare(t1, t2);
if (delta == 0) {
delta = o1.compareTo(o2);
}
return delta;
}
});
sm.putAll(map);
return sm;
}
/**
* @return all the modules that start with some token (from this manager and others involved)
*/
@Override
public SortedMap<ModulesKey, ModulesKey> getAllModulesStartingWith(String strStartingWith) {
SortedMap<ModulesKey, ModulesKey> ret = new TreeMap<ModulesKey, ModulesKey>();
IModulesManager[] managersInvolved = this.getManagersInvolved(true);
for (int i = 0; i < managersInvolved.length; i++) {
ret.putAll(managersInvolved[i].getAllDirectModulesStartingWith(strStartingWith));
}
return ret;
}
@Override
protected void writeParamsEntry(StringBuilder sb, ExecutionInfo execInfo, List<QueryInfo> queryInfoList) {
sb.append("Params:[");
for (QueryInfo queryInfo : queryInfoList) {
boolean firstArg = true;
for (Map<String, Object> paramMap : queryInfo.getQueryArgsList()) {
if(!firstArg) {
sb.append(", ");
} else {
firstArg = false;
}
SortedMap<String, Object> sortedParamMap = new TreeMap<>( new StringAsIntegerComparator());
sortedParamMap.putAll(paramMap);
sb.append("(");
boolean firstParam = true;
for (Map.Entry<String, Object> paramEntry : sortedParamMap.entrySet()) {
if(!firstParam) {
sb.append(", ");
} else {
firstParam = false;
}
Object parameter = paramEntry.getValue();
if(parameter != null && parameter.getClass().isArray()) {
sb.append(arrayToString(parameter));
} else {
sb.append(parameter);
}
}
sb.append(")");
}
}
sb.append("]");
}
@SuppressWarnings("unchecked")
private static StringBuffer toStringBuffer(Map<String, Object> unsortedMap, int indent)
{
StringBuffer tabs = new StringBuffer();
for (int i = 0; i < indent; i++)
{
tabs.append("\t");
}
StringBuffer sb = new StringBuffer();
SortedMap<String, Object> map = new TreeMap<String, Object>();
map.putAll(unsortedMap);
for (Map.Entry<String, Object> entry : map.entrySet())
{
if (entry.getValue() instanceof Map)
{
sb.append(tabs).append(entry.getKey()).append(":").append(entry.getValue().getClass()).append("\n");
sb.append(JSONtoFmModel.toStringBuffer((Map<String, Object>)entry.getValue(), indent+1));
}
else if (entry.getValue() instanceof List)
{
sb.append(tabs).append("[\n");
List l = (List)entry.getValue();
for (int i = 0; i < l.size(); i++)
{
sb.append(tabs).append(l.get(i)).append(":").append((l.get(i) != null) ? l.get(i).getClass() : "null").append("\n");
}
sb.append(tabs).append("]\n");
}
else
{
sb.append(tabs).append(entry.getKey()).append(":").append(entry.getValue()).append(":").append((entry.getValue() != null ? entry.getValue().getClass() : "null")).append("\n");
}
}
return sb;
}
/**
* We can't find generated resources. If a layout uses them, the layout won't render correctly.
*/
private void reportGeneratedResources(
AndroidResourceModule resourceModule, TargetMap targetMap, ArtifactLocationDecoder decoder) {
Map<String, Throwable> brokenClasses = logger.getBrokenClasses();
if (brokenClasses == null || brokenClasses.isEmpty()) {
return;
}
// Sorted entries for deterministic error message.
SortedMap<ArtifactLocation, TargetIdeInfo> generatedResources =
Maps.newTreeMap(getGeneratedResources(targetMap.get(resourceModule.targetKey)));
for (TargetKey dependency : resourceModule.transitiveResourceDependencies) {
generatedResources.putAll(getGeneratedResources(targetMap.get(dependency)));
}
if (generatedResources.isEmpty()) {
return;
}
HtmlBuilder builder = new HtmlBuilder();
builder.add("Generated resources will not be discovered by the IDE:");
builder.beginList();
for (Map.Entry<ArtifactLocation, TargetIdeInfo> entry : generatedResources.entrySet()) {
ArtifactLocation resource = entry.getKey();
TargetIdeInfo target = entry.getValue();
builder.listItem().add(resource.getRelativePath()).add(" from ");
addTargetLink(builder, target, decoder);
}
builder
.endList()
.add("Please avoid using generated resources, ")
.addLink("then ", "sync the project", " ", getLinkManager().createSyncProjectUrl())
.addLink("and ", "refresh the layout", ".", getLinkManager().createRefreshRenderUrl());
addIssue()
.setSeverity(HighlightSeverity.ERROR, HIGH_PRIORITY + 1) // Reported above broken classes
.setSummary("Generated resources")
.setHtmlContent(builder)
.build();
}
public static int compareTo(Map a, Map b) {
int lastComparison = compareTo(a.size(), b.size());
if (lastComparison != 0) {
return lastComparison;
}
// Sort a and b so we can compare them.
SortedMap sortedA = new TreeMap(comparator);
sortedA.putAll(a);
Iterator<Map.Entry> iterA = sortedA.entrySet().iterator();
SortedMap sortedB = new TreeMap(comparator);
sortedB.putAll(b);
Iterator<Map.Entry> iterB = sortedB.entrySet().iterator();
// Compare each item.
while (iterA.hasNext() && iterB.hasNext()) {
Map.Entry entryA = iterA.next();
Map.Entry entryB = iterB.next();
lastComparison = comparator.compare(entryA.getKey(), entryB.getKey());
if (lastComparison != 0) {
return lastComparison;
}
lastComparison = comparator.compare(entryA.getValue(), entryB.getValue());
if (lastComparison != 0) {
return lastComparison;
}
}
return 0;
}
private Set<Entry<Integer, BiomeColorJson>> getSortedColorMapEntries() {
if(colorMap == null) {
return Collections.emptySet();
}
SortedMap<Integer, BiomeColorJson> result = new TreeMap<>(Integer::compare);
result.putAll(colorMap);
return result.entrySet();
}
/** @return a map with all statistics sorted by name.
* The Object values can be either Double or String
*/
public SortedMap<String, Object> getAllStatisticsAsObjectsSorted() {
final SortedMap<String, Object> res = new TreeMap<String, Object>();
if (m_stringStats != null) {
res.putAll(m_stringStats);
}
if (m_doubleStats != null) {
res.putAll(m_doubleStats);
}
return res;
}
private static SortedMap<ArtifactLocation, TargetIdeInfo> getGeneratedResources(
TargetIdeInfo target) {
if (target == null || target.getAndroidIdeInfo() == null) {
return Collections.emptySortedMap();
}
SortedMap<ArtifactLocation, TargetIdeInfo> generatedResources = Maps.newTreeMap();
generatedResources.putAll(
target.getAndroidIdeInfo().getResources().stream()
.filter(ArtifactLocation::isGenerated)
.collect(Collectors.toMap(Function.identity(), resource -> target)));
return generatedResources;
}
@Override
public void write(Json json) {
BladeJson bjson = (BladeJson) json;
if (bjson.getMode() == Mode.MODEL) {
SortedMap<String, AnimationDesc> sortedAnims = new TreeMap<>();
sortedAnims.putAll(fanims);
json.writeValue("fanims", sortedAnims, sortedAnims.getClass(), null);
json.writeValue("initAnimation", initAnimation);
json.writeValue("orgAlign", orgAlign);
} else {
String currentAnimationId = null;
if (currentAnimation != null)
currentAnimationId = currentAnimation.id;
json.writeValue("currentAnimation", currentAnimationId);
json.writeValue("flipX", flipX);
}
}
/**
* Returns a Map whose keys are all of the possible formats into which data
* in the specified DataFlavors can be translated. The value of each key
* is the DataFlavor in which the Transferable's data should be requested
* when converting to the format.
* <p>
* The map keys are sorted according to the native formats preference
* order.
*
* @param flavors the data flavors
* @param map the FlavorTable which contains mappings between
* DataFlavors and data formats
* @throws NullPointerException if flavors or map is <code>null</code>
*/
public SortedMap <Long, DataFlavor> getFormatsForFlavors(
DataFlavor[] flavors, FlavorTable map)
{
Map <Long,DataFlavor> formatMap =
new HashMap <> (flavors.length);
Map <Long,DataFlavor> textPlainMap =
new HashMap <> (flavors.length);
// Maps formats to indices that will be used to sort the formats
// according to the preference order.
// Larger index value corresponds to the more preferable format.
Map indexMap = new HashMap(flavors.length);
Map textPlainIndexMap = new HashMap(flavors.length);
int currentIndex = 0;
// Iterate backwards so that preferred DataFlavors are used over
// other DataFlavors. (See javadoc for
// Transferable.getTransferDataFlavors.)
for (int i = flavors.length - 1; i >= 0; i--) {
DataFlavor flavor = flavors[i];
if (flavor == null) continue;
// Don't explicitly test for String, since it is just a special
// case of Serializable
if (flavor.isFlavorTextType() ||
flavor.isFlavorJavaFileListType() ||
DataFlavor.imageFlavor.equals(flavor) ||
flavor.isRepresentationClassSerializable() ||
flavor.isRepresentationClassInputStream() ||
flavor.isRepresentationClassRemote())
{
List natives = map.getNativesForFlavor(flavor);
currentIndex += natives.size();
for (Iterator iter = natives.iterator(); iter.hasNext(); ) {
Long lFormat =
getFormatForNativeAsLong((String)iter.next());
Integer index = Integer.valueOf(currentIndex--);
formatMap.put(lFormat, flavor);
indexMap.put(lFormat, index);
// SystemFlavorMap.getNativesForFlavor will return
// text/plain natives for all text/*. While this is good
// for a single text/* flavor, we would prefer that
// text/plain native data come from a text/plain flavor.
if (("text".equals(flavor.getPrimaryType()) &&
"plain".equals(flavor.getSubType())) ||
flavor.equals(DataFlavor.stringFlavor))
{
textPlainMap.put(lFormat, flavor);
textPlainIndexMap.put(lFormat, index);
}
}
currentIndex += natives.size();
}
}
formatMap.putAll(textPlainMap);
indexMap.putAll(textPlainIndexMap);
// Sort the map keys according to the formats preference order.
Comparator comparator =
new IndexOrderComparator(indexMap, IndexedComparator.SELECT_WORST);
SortedMap sortedMap = new TreeMap(comparator);
sortedMap.putAll(formatMap);
return sortedMap;
}
public void logMetrics(final Map<String, Timer> stats) {
final SortedMap<String, Timer> m = new TreeMap<String, Timer>();
m.putAll(stats);
this.reporter.report(EMPTY_GUAGES, EMPTY_COUNTERS, EMPTY_HISTOGRAMS, EMPTY_METERS, m);
}
/**
* Parses configuration files from the uploaded user data and produces {@link VendorConfiguration
* vendor-specific configurations} serialized to the given output path.
*
* <p>This function should be named better, but it's called by the {@code -sv} argument to Batfish
* so leaving as-is for now.
*/
private Answer serializeVendorConfigs(NetworkSnapshot snapshot) {
Answer answer = new Answer();
boolean configsFound = false;
ParseVendorConfigurationAnswerElement answerElement =
new ParseVendorConfigurationAnswerElement();
answerElement.setVersion(BatfishVersion.getVersionStatic());
if (_settings.getVerboseParse()) {
answer.addAnswerElement(answerElement);
}
// look for host configs and overlay configs in the `hosts/` subfolder of the upload.
SortedMap<String, VendorConfiguration> overlayHostConfigurations = new TreeMap<>();
if (hasHostConfigs(snapshot)) {
overlayHostConfigurations.putAll(serializeHostConfigs(snapshot, answerElement));
configsFound = true;
}
// look for network configs in the `configs/` subfolder of the upload.
if (serializeNetworkConfigs(snapshot, answerElement, overlayHostConfigurations)) {
configsFound = true;
}
// look for AWS VPC configs in the `aws_configs/` subfolder of the upload.
if (serializeAwsConfigs(snapshot, answerElement)) {
configsFound = true;
}
if (!configsFound) {
throw new BatfishException("No valid configurations found in snapshot");
}
// serialize warnings
try {
_storage.storeParseVendorConfigurationAnswerElement(answerElement, snapshot);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return answer;
}
/**
* Returns a Map whose keys are all of the possible formats into which data
* in the specified DataFlavors can be translated. The value of each key
* is the DataFlavor in which the Transferable's data should be requested
* when converting to the format.
* <p>
* The map keys are sorted according to the native formats preference
* order.
*
* @param flavors the data flavors
* @param map the FlavorTable which contains mappings between
* DataFlavors and data formats
* @throws NullPointerException if flavors or map is <code>null</code>
*/
public SortedMap <Long, DataFlavor> getFormatsForFlavors(
DataFlavor[] flavors, FlavorTable map)
{
Map <Long,DataFlavor> formatMap =
new HashMap <> (flavors.length);
Map <Long,DataFlavor> textPlainMap =
new HashMap <> (flavors.length);
// Maps formats to indices that will be used to sort the formats
// according to the preference order.
// Larger index value corresponds to the more preferable format.
Map indexMap = new HashMap(flavors.length);
Map textPlainIndexMap = new HashMap(flavors.length);
int currentIndex = 0;
// Iterate backwards so that preferred DataFlavors are used over
// other DataFlavors. (See javadoc for
// Transferable.getTransferDataFlavors.)
for (int i = flavors.length - 1; i >= 0; i--) {
DataFlavor flavor = flavors[i];
if (flavor == null) continue;
// Don't explicitly test for String, since it is just a special
// case of Serializable
if (flavor.isFlavorTextType() ||
flavor.isFlavorJavaFileListType() ||
DataFlavor.imageFlavor.equals(flavor) ||
flavor.isRepresentationClassSerializable() ||
flavor.isRepresentationClassInputStream() ||
flavor.isRepresentationClassRemote())
{
List natives = map.getNativesForFlavor(flavor);
currentIndex += natives.size();
for (Iterator iter = natives.iterator(); iter.hasNext(); ) {
Long lFormat =
getFormatForNativeAsLong((String)iter.next());
Integer index = Integer.valueOf(currentIndex--);
formatMap.put(lFormat, flavor);
indexMap.put(lFormat, index);
// SystemFlavorMap.getNativesForFlavor will return
// text/plain natives for all text/*. While this is good
// for a single text/* flavor, we would prefer that
// text/plain native data come from a text/plain flavor.
if (("text".equals(flavor.getPrimaryType()) &&
"plain".equals(flavor.getSubType())) ||
flavor.equals(DataFlavor.stringFlavor))
{
textPlainMap.put(lFormat, flavor);
textPlainIndexMap.put(lFormat, index);
}
}
currentIndex += natives.size();
}
}
formatMap.putAll(textPlainMap);
indexMap.putAll(textPlainIndexMap);
// Sort the map keys according to the formats preference order.
Comparator comparator =
new IndexOrderComparator(indexMap, IndexedComparator.SELECT_WORST);
SortedMap sortedMap = new TreeMap(comparator);
sortedMap.putAll(formatMap);
return sortedMap;
}
/**
* Returns a Map whose keys are all of the possible formats into which data
* in the specified DataFlavors can be translated. The value of each key
* is the DataFlavor in which the Transferable's data should be requested
* when converting to the format.
* <p>
* The map keys are sorted according to the native formats preference
* order.
*
* @param flavors the data flavors
* @param map the FlavorTable which contains mappings between
* DataFlavors and data formats
* @throws NullPointerException if flavors or map is <code>null</code>
*/
public SortedMap <Long, DataFlavor> getFormatsForFlavors(
DataFlavor[] flavors, FlavorTable map)
{
Map <Long,DataFlavor> formatMap =
new HashMap <> (flavors.length);
Map <Long,DataFlavor> textPlainMap =
new HashMap <> (flavors.length);
// Maps formats to indices that will be used to sort the formats
// according to the preference order.
// Larger index value corresponds to the more preferable format.
Map indexMap = new HashMap(flavors.length);
Map textPlainIndexMap = new HashMap(flavors.length);
int currentIndex = 0;
// Iterate backwards so that preferred DataFlavors are used over
// other DataFlavors. (See javadoc for
// Transferable.getTransferDataFlavors.)
for (int i = flavors.length - 1; i >= 0; i--) {
DataFlavor flavor = flavors[i];
if (flavor == null) continue;
// Don't explicitly test for String, since it is just a special
// case of Serializable
if (flavor.isFlavorTextType() ||
flavor.isFlavorJavaFileListType() ||
DataFlavor.imageFlavor.equals(flavor) ||
flavor.isRepresentationClassSerializable() ||
flavor.isRepresentationClassInputStream() ||
flavor.isRepresentationClassRemote())
{
List natives = map.getNativesForFlavor(flavor);
currentIndex += natives.size();
for (Iterator iter = natives.iterator(); iter.hasNext(); ) {
Long lFormat =
getFormatForNativeAsLong((String)iter.next());
Integer index = Integer.valueOf(currentIndex--);
formatMap.put(lFormat, flavor);
indexMap.put(lFormat, index);
// SystemFlavorMap.getNativesForFlavor will return
// text/plain natives for all text/*. While this is good
// for a single text/* flavor, we would prefer that
// text/plain native data come from a text/plain flavor.
if (("text".equals(flavor.getPrimaryType()) &&
"plain".equals(flavor.getSubType())) ||
flavor.equals(DataFlavor.stringFlavor))
{
textPlainMap.put(lFormat, flavor);
textPlainIndexMap.put(lFormat, index);
}
}
currentIndex += natives.size();
}
}
formatMap.putAll(textPlainMap);
indexMap.putAll(textPlainIndexMap);
// Sort the map keys according to the formats preference order.
Comparator comparator =
new IndexOrderComparator(indexMap, IndexedComparator.SELECT_WORST);
SortedMap sortedMap = new TreeMap(comparator);
sortedMap.putAll(formatMap);
return sortedMap;
}
/**
* Returns a Map whose keys are all of the possible formats into which data
* in the specified DataFlavors can be translated. The value of each key
* is the DataFlavor in which the Transferable's data should be requested
* when converting to the format.
* <p>
* The map keys are sorted according to the native formats preference
* order.
*
* @param flavors the data flavors
* @param map the FlavorTable which contains mappings between
* DataFlavors and data formats
* @throws NullPointerException if flavors or map is <code>null</code>
*/
public SortedMap <Long, DataFlavor> getFormatsForFlavors(
DataFlavor[] flavors, FlavorTable map)
{
Map <Long,DataFlavor> formatMap =
new HashMap <> (flavors.length);
Map <Long,DataFlavor> textPlainMap =
new HashMap <> (flavors.length);
// Maps formats to indices that will be used to sort the formats
// according to the preference order.
// Larger index value corresponds to the more preferable format.
Map indexMap = new HashMap(flavors.length);
Map textPlainIndexMap = new HashMap(flavors.length);
int currentIndex = 0;
// Iterate backwards so that preferred DataFlavors are used over
// other DataFlavors. (See javadoc for
// Transferable.getTransferDataFlavors.)
for (int i = flavors.length - 1; i >= 0; i--) {
DataFlavor flavor = flavors[i];
if (flavor == null) continue;
// Don't explicitly test for String, since it is just a special
// case of Serializable
if (flavor.isFlavorTextType() ||
flavor.isFlavorJavaFileListType() ||
DataFlavor.imageFlavor.equals(flavor) ||
flavor.isRepresentationClassSerializable() ||
flavor.isRepresentationClassInputStream() ||
flavor.isRepresentationClassRemote())
{
List natives = map.getNativesForFlavor(flavor);
currentIndex += natives.size();
for (Iterator iter = natives.iterator(); iter.hasNext(); ) {
Long lFormat =
getFormatForNativeAsLong((String)iter.next());
Integer index = Integer.valueOf(currentIndex--);
formatMap.put(lFormat, flavor);
indexMap.put(lFormat, index);
// SystemFlavorMap.getNativesForFlavor will return
// text/plain natives for all text/*. While this is good
// for a single text/* flavor, we would prefer that
// text/plain native data come from a text/plain flavor.
if (("text".equals(flavor.getPrimaryType()) &&
"plain".equals(flavor.getSubType())) ||
flavor.equals(DataFlavor.stringFlavor))
{
textPlainMap.put(lFormat, flavor);
textPlainIndexMap.put(lFormat, index);
}
}
currentIndex += natives.size();
}
}
formatMap.putAll(textPlainMap);
indexMap.putAll(textPlainIndexMap);
// Sort the map keys according to the formats preference order.
Comparator comparator =
new IndexOrderComparator(indexMap, IndexedComparator.SELECT_WORST);
SortedMap sortedMap = new TreeMap(comparator);
sortedMap.putAll(formatMap);
return sortedMap;
}
/**
* Computes the difference between two sorted maps, using the comparator of
* the left map, or {@code Ordering.natural()} if the left map uses the
* natural ordering of its elements. This difference is an immutable snapshot
* of the state of the maps at the time this method is called. It will never
* change, even if the maps change at a later time.
*
* <p>Since this method uses {@code TreeMap} instances internally, the keys of
* the right map must all compare as distinct according to the comparator
* of the left map.
*
* <p><b>Note:</b>If you only need to know whether two sorted maps have the
* same mappings, call {@code left.equals(right)} instead of this method.
*
* @param left the map to treat as the "left" map for purposes of comparison
* @param right the map to treat as the "right" map for purposes of comparison
* @return the difference between the two maps
* @since 11.0
*/
public static <K, V> SortedMapDifference<K, V> difference(
SortedMap<K, ? extends V> left, Map<? extends K, ? extends V> right) {
checkNotNull(left);
checkNotNull(right);
Comparator<? super K> comparator = orNaturalOrder(left.comparator());
SortedMap<K, V> onlyOnLeft = Maps.newTreeMap(comparator);
SortedMap<K, V> onlyOnRight = Maps.newTreeMap(comparator);
onlyOnRight.putAll(right); // will whittle it down
SortedMap<K, V> onBoth = Maps.newTreeMap(comparator);
SortedMap<K, MapDifference.ValueDifference<V>> differences = Maps.newTreeMap(comparator);
doDifference(left, right, Equivalence.equals(), onlyOnLeft, onlyOnRight, onBoth, differences);
return new SortedMapDifferenceImpl<K, V>(onlyOnLeft, onlyOnRight, onBoth, differences);
}
/**
* Computes the difference between two sorted maps, using the comparator of
* the left map, or {@code Ordering.natural()} if the left map uses the
* natural ordering of its elements. This difference is an immutable snapshot
* of the state of the maps at the time this method is called. It will never
* change, even if the maps change at a later time.
*
* <p>Since this method uses {@code TreeMap} instances internally, the keys of
* the right map must all compare as distinct according to the comparator
* of the left map.
*
* <p><b>Note:</b>If you only need to know whether two sorted maps have the
* same mappings, call {@code left.equals(right)} instead of this method.
*
* @param left the map to treat as the "left" map for purposes of comparison
* @param right the map to treat as the "right" map for purposes of comparison
* @return the difference between the two maps
* @since 11.0
*/
public static <K, V> SortedMapDifference<K, V> difference(SortedMap<K, ? extends V> left, Map<? extends K, ? extends V> right) {
checkNotNull(left);
checkNotNull(right);
Comparator<? super K> comparator = orNaturalOrder(left.comparator());
SortedMap<K, V> onlyOnLeft = Maps.newTreeMap(comparator);
SortedMap<K, V> onlyOnRight = Maps.newTreeMap(comparator);
onlyOnRight.putAll(right); // will whittle it down
SortedMap<K, V> onBoth = Maps.newTreeMap(comparator);
SortedMap<K, MapDifference.ValueDifference<V>> differences = Maps.newTreeMap(comparator);
doDifference(left, right, Equivalence.equals(), onlyOnLeft, onlyOnRight, onBoth, differences);
return new SortedMapDifferenceImpl<K, V>(onlyOnLeft, onlyOnRight, onBoth, differences);
}
/**
* Computes the difference between two sorted maps, using the comparator of
* the left map, or {@code Ordering.natural()} if the left map uses the
* natural ordering of its elements. This difference is an immutable snapshot
* of the state of the maps at the time this method is called. It will never
* change, even if the maps change at a later time.
*
* <p>Since this method uses {@code TreeMap} instances internally, the keys of
* the right map must all compare as distinct according to the comparator
* of the left map.
*
* <p><b>Note:</b>If you only need to know whether two sorted maps have the
* same mappings, call {@code left.equals(right)} instead of this method.
*
* @param left the map to treat as the "left" map for purposes of comparison
* @param right the map to treat as the "right" map for purposes of comparison
* @return the difference between the two maps
* @since 11.0
*/
public static <K, V> SortedMapDifference<K, V> difference(SortedMap<K, ? extends V> left, Map<? extends K, ? extends V> right) {
checkNotNull(left);
checkNotNull(right);
Comparator<? super K> comparator = orNaturalOrder(left.comparator());
SortedMap<K, V> onlyOnLeft = Maps.newTreeMap(comparator);
SortedMap<K, V> onlyOnRight = Maps.newTreeMap(comparator);
onlyOnRight.putAll(right); // will whittle it down
SortedMap<K, V> onBoth = Maps.newTreeMap(comparator);
SortedMap<K, MapDifference.ValueDifference<V>> differences = Maps.newTreeMap(comparator);
doDifference(left, right, Equivalence.equals(), onlyOnLeft, onlyOnRight, onBoth, differences);
return new SortedMapDifferenceImpl<K, V>(onlyOnLeft, onlyOnRight, onBoth, differences);
}