-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use map.putIfAbsent() or map.computeIfAbsent() as appropriate instead of containsKey() + put() #7764
Conversation
Merging changes from master branch of apache/incubator-druid repo
Checking the failures. |
The test error looks potentially legitimate; please check this test and any others referenced in the Travis CI report:
|
.idea/inspectionProfiles/Druid.xml
Outdated
@@ -306,6 +303,11 @@ | |||
<constraint name="x" maxCount="2147483647" within="" contains="" /> | |||
<constraint name="ImmutableMap" regexp="Immutable.*" within="" contains="" /> | |||
</searchConfiguration> | |||
<searchConfiguration name="Use Map.putIfAbsent() instead of containsKey() + put()" created="1558868694225" text="if (!$m$.containsKey($k$)) { $m$.put($k$, $v$); }" recursive="false" caseInsensitive="true" type="JAVA"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't always good advice: in particular, if v
is expensive to compute then computeIfAbsent should be used instead of putIfAbsent. This is because putIfAbsent computes v
eagerly, whereas containsKey + put (or computeIfAbsent) computes v
lazily. This can also have a deeper effect on behavior, if computation of v
has side effects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After reviewing the rest of the patch, it seems like computeIfAbsent is appropriate more often than putIfAbsent, so the recommendation here should reflect that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure @gianm , I'll make the necessary changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've made the changes. Some of the changes are straight forward. I'll comment on those respective changes which are notable.
if (!hyperLogLogs.containsKey(interval)) { | ||
hyperLogLogs.put(interval, HyperLogLogCollector.makeLatestCollector()); | ||
} | ||
hyperLogLogs.putIfAbsent(interval, HyperLogLogCollector.makeLatestCollector()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good candidate for computeIfAbsent
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
if (!identifiersByDataSource.containsKey(identifier.getDataSource())) { | ||
identifiersByDataSource.put(identifier.getDataSource(), new HashSet<>()); | ||
} | ||
identifiersByDataSource.putIfAbsent(identifier.getDataSource(), new HashSet<>()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good candidate for computeIfAbsent
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
if (!hllCollectors.containsKey(interval)) { | ||
hllCollectors.put(interval, Optional.of(HyperLogLogCollector.makeLatestCollector())); | ||
} | ||
hllCollectors.putIfAbsent(interval, Optional.of(HyperLogLogCollector.makeLatestCollector())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good candidate for computeIfAbsent
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
if (!segmentFileMap.containsKey(segment)) { | ||
segmentFileMap.put(segment, segmentLoader.getSegmentFiles(segment)); | ||
} | ||
segmentFileMap.putIfAbsent(segment, segmentLoader.getSegmentFiles(segment)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be computeIfAbsent
, since there are side effects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
if (!serverExpectations.containsKey(lastServer)) { | ||
serverExpectations.put(lastServer, new ServerExpectations(lastServer, makeMock(mocks, QueryRunner.class))); | ||
} | ||
serverExpectations.putIfAbsent(lastServer, new ServerExpectations(lastServer, makeMock(mocks, QueryRunner.class))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another good candidate for computeIfAbsent
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
if (!newContext.containsKey(PlannerContext.CTX_SQL_QUERY_ID)) { | ||
newContext.put(PlannerContext.CTX_SQL_QUERY_ID, UUID.randomUUID().toString()); | ||
} | ||
newContext.putIfAbsent(PlannerContext.CTX_SQL_QUERY_ID, UUID.randomUUID().toString()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another good candidate for computeIfAbsent
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
if (!timelines.containsKey(descriptor.getDataSource())) { | ||
timelines.put(descriptor.getDataSource(), new VersionedIntervalTimeline<>(Ordering.natural())); | ||
} | ||
timelines.putIfAbsent(descriptor.getDataSource(), new VersionedIntervalTimeline<>(Ordering.natural())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another good candidate for computeIfAbsent
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
.idea/inspectionProfiles/Druid.xml
Outdated
@@ -88,9 +88,6 @@ | |||
<inspection_tool class="JSRedeclarationOfBlockScope" enabled="true" level="Non-TeamCity Error" enabled_by_default="true" /> | |||
<inspection_tool class="JSReferencingArgumentsOutsideOfFunction" enabled="true" level="Non-TeamCity Error" enabled_by_default="true" /> | |||
<inspection_tool class="Java8MapForEach" enabled="true" level="ERROR" enabled_by_default="true" /> | |||
<inspection_tool class="JavadocReference" enabled="true" level="ERROR" enabled_by_default="true"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reverted this change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reverted this change.
.idea/inspectionProfiles/Druid.xml
Outdated
@@ -161,7 +158,7 @@ | |||
<searchConfiguration name="Suboptimal IndexedInts iteration" text="$x$ < $y$.size()" recursive="false" caseInsensitive="true" type="JAVA"> | |||
<constraint name="__context__" target="true" within="" contains="" /> | |||
<constraint name="x" within="" contains="" /> | |||
<constraint name="y" nameOfExprType="IndexedInts" exprTypeWithinHierarchy="true" within="" contains="" /> | |||
<constraint name="y" nameOfExprType="IndexedInts" expressionTypes="IndexedInts" exprTypeWithinHierarchy="true" within="" contains="" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When using different versions of IntelliJ IDEA, it makes some seemingly arbitrary changes to the config by itself. As long as it doesn't break the TeamCity build (and if the PR author uses the latest version of IntelliJ), it should be fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@leventov, thanks for the info. I've reverted the changes auto made by the IDE.
|
||
segmentFileMap.computeIfAbsent(segment, k -> { | ||
try { | ||
return segmentLoader.getSegmentFiles(segment); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
segmentLoader.getSegmentFiles(segment) throws SegmentLoadingException, which needs to be caught and re thrown as RuntimeException. This makes the outer try catch redundant (compilation error) as the SegmentLoadingException has already been caught.
} | ||
catch (SegmentLoadingException e) { | ||
throw new RuntimeException(e); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Outer try/catch block removed.
if (!uniqueMetrics.containsKey(metric)) { | ||
uniqueMetrics.put(metric, index++); | ||
uniqueMetrics.computeIfAbsent(metric, k -> { | ||
return index[0]++; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using index variable as int as is, the compiler complains "Variables used in lambda should be final or effectively final"
. The fix is to use an integer array with one element. Let me know if this is right.
@gianm , @leventov
This is the line. Why should ConcurrentMap changed to ConcurrentHashMap type here ? |
This check was added in #6898, I think maybe this comment is relevant to what it is trying to enforce. |
…sent() is called should be assigned into variables of ConcurrentHashMap type, not ConcurrentMap
Thanks @clintropolis this helps. |
@clintropolis the reference place with the explanation is now here: https://github.com/code-review-checklists/java-concurrency#chm-type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
@leventov Please review. |
The PR doesn't require my review because it has one approval from a committer and it's not tagged |
Thanks @leventov. |
Fix #7316.
if(!map.containsKey(some_key)) {
key.put(some_key, some_value);
}
The above map usage pattern has been replaced with map.putIfAbsent()
A new search configuration got updated in .idea/inspectionProfiles/Druid.xml.