-
Notifications
You must be signed in to change notification settings - Fork 1.5k
feat(DEVELOP): create hashMap #1598
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
base: master
Are you sure you want to change the base?
Conversation
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.
Review Summary
I’m requesting changes because there is a critical correctness bug that can cause runtime failures, plus a couple of checklist violations to address.
Critical blocker (must fix to pass):
- Negative bucket index due to
Math.abs(hash)
whenhash == Integer.MIN_VALUE
(lines: put ~33, getValue ~67, resize rehash ~95). This can produce a negative index and lead toArrayIndexOutOfBoundsException
. Fix by computing a non-negative index, e.g.int idx = (hash & 0x7fffffff) % capacity;
(or bit-mask if capacity is a power of two). Apply consistently in put/getValue/resize.
Other required checklist fixes:
- Private members order: the private inner
Node
class is declared before public API (lines 10–19). MoveNode
to the end of the class (after public methods) to comply with “private after public”. - Encapsulation:
resize()
is declaredpublic
(around line 88) but is an internal helper. Change it toprivate
and keep it after public methods.
Minor improvements (nice to have):
- Replace magic literal
2
in capacity growth (line ~89table.length * 2
) with a constant, e.g.private static final int RESIZE_MULTIPLIER = 2;
. - Remove leading/redundant blank lines (top of file line 2 and any extra empty lines inside methods) per checklist.
Your core logic (chaining, updates, null key/value handling, resize flow) is solid. Address the index calculation and checklist items above and you should be in great shape. Keep going!
✨ Please rate this review in the Platform's notification center1. I will be grateful for your feedback! ✨
Important
Fix the issues, commit the changes, and then re-request my review using the Re-request review
button2 in the Reviewers tab.
Tip
If you have any comments about this review, please leave a message in the Add a comment section below and mention me with the @mateacademy-ai-mentor
tag3.
I will read your message during my next review of your pull request. Please do not reply directly to my comments, as that feature is not supported yet.
Caution
Do not close the pull request until the review is complete. Closing it early can lead to unexpected behavior and disrupt the review process.
Footnotes
private static class Node<K, V> { | ||
private final K key; | ||
private V value; | ||
private Node<K, V> next; | ||
|
||
public Node(K key, V value) { | ||
this.key = key; | ||
this.value = value; | ||
} | ||
} |
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 violates checklist item: "Private methods and classes should be after public ones in your class." The private inner Node
class is declared at the top of the class (lines 10–19). Move the Node
class to after the public methods (for example, at the end of the class) so private helpers follow the public API. See checklist guidance: .
public void resize() { | ||
int newCapacity = table.length * 2; | ||
|
||
Node<K, V>[] newTable = new Node[newCapacity]; | ||
|
||
for (Node<K, V> node : table) { | ||
while (node != null) { | ||
int newIndex = node.key == null ? 0 : Math.abs(node.key.hashCode()) % newCapacity; | ||
Node<K, V> nextNode = node.next; | ||
|
||
node.next = newTable[newIndex]; | ||
newTable[newIndex] = node; | ||
node = nextNode; | ||
} | ||
} | ||
|
||
table = newTable; | ||
threshold = (int) (newCapacity * LOAD_FACTOR); | ||
} |
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 violates checklist item: "If the method has only a utility purpose and is used only inside the same class, it should not be public
. Keep your code as close as possible to follow the encapsulation principle." The resize()
method is declared public
(line 88) but is an internal helper used only by this class. Change its visibility to private
and keep it after public methods. See checklist guidance: .
} | ||
|
||
public void resize() { | ||
int newCapacity = table.length * 2; |
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 violates checklist item: "Any magic numbers should be constants". The resize multiplier is used as a literal at line 89 (table.length * 2
). Introduce a named constant such as private static final int RESIZE_MULTIPLIER = 2;
and use it to compute the new capacity so numeric intent is explicit. See checklist guidance: .
int index = key == null ? 0 : Math.abs(key.hashCode()) % table.length; | ||
Node<K, V> newNode = new Node<>(key, value); | ||
|
||
if (table[index] == null) { | ||
table[index] = newNode; | ||
size++; | ||
return; | ||
} | ||
|
||
Node<K, V> currentNode = table[index]; | ||
|
||
while (true) { | ||
if ((currentNode.key == null && key == null) | ||
|| (currentNode.key != null && currentNode.key.equals(key))) { | ||
currentNode.value = value; | ||
return; | ||
} | ||
|
||
if (currentNode.next == null) { | ||
currentNode.next = newNode; | ||
size++; | ||
return; | ||
} | ||
|
||
currentNode = currentNode.next; | ||
} | ||
} | ||
|
||
@Override | ||
public V getValue(K key) { | ||
if (table == null) { | ||
return null; | ||
} | ||
|
||
int index = key == null ? 0 : Math.abs(key.hashCode()) % table.length; | ||
|
||
Node<K, V> currentNode = table[index]; | ||
|
||
while (currentNode != null) { | ||
if ((currentNode.key == null && key == null) | ||
|| (currentNode.key != null && currentNode.key.equals(key))) { | ||
return currentNode.value; | ||
} | ||
|
||
currentNode = currentNode.next; | ||
} | ||
|
||
return null; | ||
} | ||
|
||
@Override | ||
public int getSize() { | ||
return 0; | ||
return size; | ||
} | ||
|
||
public void resize() { | ||
int newCapacity = table.length * 2; | ||
|
||
Node<K, V>[] newTable = new Node[newCapacity]; | ||
|
||
for (Node<K, V> node : table) { | ||
while (node != null) { | ||
int newIndex = node.key == null ? 0 : Math.abs(node.key.hashCode()) % newCapacity; |
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.
Correctness issue (must fix): computing bucket index with Math.abs(key.hashCode()) % capacity
can yield a negative index when hashCode()
equals Integer.MIN_VALUE
. This pattern appears in put
(line 33), getValue
(line 67), and resize
rehashing (line 95). Replace with a safe computation such as (key.hashCode() & 0x7fffffff) % capacity
or use masking when capacity is a power of two. Without this change, the code can throw ArrayIndexOutOfBoundsException at runtime.
@@ -1,19 +1,107 @@ | |||
package core.basesyntax; | |||
|
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 violates checklist item: "Don't begin class or method implementation with empty line. Remove all redundant empty lines, be careful :)" There is a leading redundant empty line at the top of the file (line 2) and several redundant blank lines inside the class. Remove leading and unnecessary blank lines at method/class starts to comply with the style checklist. See checklist guidance: .
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.
Review Summary
Decision: Approve. Functionality and requirements are met; only minor style issues remain.
- Your
MyHashMap
correctly implementsput
,getValue
, andgetSize
, handles updates without increasing size, manages collisions via chaining, and resizes/rehashes properly. The non-negative index computation resolves the previous critical bug. - The remaining issues are stylistic: there are several redundant empty lines (e.g., at the top of the class, between fields, before local logic in
put
, inside theput
loop, aroundgetValue
index calculation, insidegetValue
, beforeresize
, and insideresize
). These violate the checklist rule to avoid starting class/method bodies with blank lines and to remove redundant empty lines. Please remove those blanks to fully comply. - Optional polish: consider adding a brief comment explaining the bitmask in
getIndex
and, if desired, a localized@SuppressWarnings("unchecked")
aroundnew Node[...]
array creation.
Nice work on correctness and structure—just tidy the extra blank lines to align with the checklist.
✨ Please rate this review in the Platform's notification center1. I will be grateful for your feedback! ✨
Footnotes
private static final int DEFAULT_CAPACITY = 16; | ||
private static final float LOAD_FACTOR = 0.75f; | ||
private static final int RESIZE_MULTIPLIER = 2; | ||
|
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.
Redundant empty line. This violates the checklist item: "Don't begin class or method implementation with empty line. Remove all redundant empty lines, be careful :)". Please remove the empty line at the top of the class to match the checklist.
private int threshold; | ||
private int size; | ||
private Node<K, V>[] table; | ||
|
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.
Redundant empty line. This violates the checklist item: "Don't begin class or method implementation with empty line. Remove all redundant empty lines, be careful :)". Please remove this extra blank line between fields.
if (size >= threshold) { | ||
resize(); | ||
} | ||
|
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.
Redundant empty line before local logic. This violates the checklist item: "Don't begin class or method implementation with empty line. Remove all redundant empty lines, be careful :)". Delete the unnecessary blank line.
|
||
int index = getIndex(key, table.length); | ||
Node<K, V> newNode = new Node<>(key, value); | ||
|
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.
Redundant empty line. This violates the checklist item: "Don't begin class or method implementation with empty line. Remove all redundant empty lines, be careful :)". Remove it to keep the file compact.
currentNode.value = value; | ||
return; | ||
} | ||
|
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.
Redundant empty line inside put loop area. This violates the checklist item: "Don't begin class or method implementation with empty line. Remove all redundant empty lines, be careful :)". Please remove.
size++; | ||
return; | ||
} | ||
|
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.
Redundant empty line. This violates the checklist item: "Don't begin class or method implementation with empty line. Remove all redundant empty lines, be careful :)". Remove this blank line.
if (table == null) { | ||
return null; | ||
} | ||
|
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.
Redundant empty line before index calculation in getValue. This violates the checklist item: "Don't begin class or method implementation with empty line. Remove all redundant empty lines, be careful :)". Please remove.
|
||
int index = getIndex(key, table.length); | ||
Node<K, V> currentNode = table[index]; | ||
|
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.
Redundant empty line inside getValue. This violates the checklist item: "Don't begin class or method implementation with empty line. Remove all redundant empty lines, be careful :)". Remove the extra blank line for consistency.
return 0; | ||
return size; | ||
} | ||
|
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.
Redundant empty line before the resize method. This violates the checklist item: "Don't begin class or method implementation with empty line. Remove all redundant empty lines, be careful :)". Please remove.
private void resize() { | ||
int newCapacity = table.length * RESIZE_MULTIPLIER; | ||
Node<K, V>[] newTable = new Node[newCapacity]; | ||
|
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.
Redundant empty line inside resize logic. This violates the checklist item: "Don't begin class or method implementation with empty line. Remove all redundant empty lines, be careful :)". Remove it to satisfy the checklist.
No description provided.