Article Directory Directory
1. Reproducing the error
Today, the test pointed me to a formal environment on ZenTao bug
, as shown in the figure below:
That is java.lang.IllegalStateException: Duplicate key 2
.
2. Analysis errors
As java.lang.IllegalStateException: Duplicate key 2
you can see, this is an java
existing error that is thrown 2个重复键
.
If you want to figure out the cause of the error, analyze it through the following steps:
- First, when you see this error message, first use and test this interface locally
postman
, as shown in the figure below:
Because it involves company security, the interface cannot be displayed.
As can be seen from the picture above, there is no problem with the local environment.
- View the logs of the formal environment, as shown below:
It can be seen from the error 第2行
that this is stream.Collectors
the error caused.
Continue looking down and find the red box, which is the location where the project code error is thrown.
So, view the code online as follows:
xxxRepository.list(new xxxQuery().setXxx(xxxId))
.stream()
.collect(Collectors.toMap(xxxEntity::getName, xxxEntity::getId));
Due to the confidentiality mechanism, the actual name xxx
has been replaced with .
Guess from xxxEntity::getName
the code: It may be that there are two identical names in the database, which Map
will be the same when converted Key
, resulting in hash
an exception, as shown in the following code:
@Data
@NoArgsConstructor
public class Student {
private BigDecimal score;
private String name;
private Integer id;
private Integer age;
@Override
public String toString() {
return JSON.toJSONString(this);
}
public Student(BigDecimal score, String name, Integer id, Integer age) {
this.score = score;
this.name = name;
this.id = id;
this.age = age;
}
public static void main(String[] args) {
Student student1 = new Student(new BigDecimal(99.5), "陈希尔", 1, 12);
Student student2 = new Student(new BigDecimal(88), "陈希尔", 2, 12);
List<Student> list = new ArrayList();
list.add(student1);
list.add(student2);
Map<String, Integer> collect =
list.stream().collect(Collectors.toMap(Student::getName, Student::getId));
Set<String> keys = collect.keySet();
String sout = "key = %s, value = %s \n";
keys.forEach(t -> System.out.format(sout, t, collect.get(t)));
}
}
Pay attention to the above sample code, the following is also modified based on this sample code.
The output is as shown below:
- Query data in the database based on the guess, as follows:
select
COUNT(`name`) as nameCount,
`name`
from
xxx_table
GROUP BY
`name`
HAVING
nameCount >= 2;
I found the problem, and it turned out that it was name
repeated, causing this error.
In actual application development, we often convert a List
query data set into a query data set Map
. So what we do here list.stream().collect()
is actually doing such a thing. It is java8
implemented in a way thatstream
it is composed of objects .type
key
entity
value
Map
In this error type
, name
the value map
in key
cannot be repeated. Repeating will cause hash
an exception.
3. Solve the problem
Now that we know the cause of the problem, we can solve it in the following ways:
-
Remove
name
duplicate records -
Modify the code to ensure that even if there are duplicate values, they can be converted
Map
.
We just need to add this line of code:
Map<String, Integer> collect =
list.stream().collect(Collectors.toMap(Student::getName, Student::getId));
Just modify it as follows:
Map<String, Integer> collect =
list.stream()
.collect(
Collectors.toMap(Student::getName, Student::getId, (entity1, entity2) -> entity1));
This code is equivalent to:
Map<String, Integer> collect =
list.stream()
.collect(
Collectors.toMap(
Student::getName,
Student::getId,
new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer entity1, Integer entity2) {
return entity1;
}
}));
After modification, the test results are as follows:
4. Important additions
Map<String, Integer> collect =
list.stream()
.collect(
Collectors.toMap(Student::getName, Student::getId, (entity1, entity2) -> entity1));
Equivalent to:
Map<String, Integer> collect =
list.stream()
.collect(
Collectors.toMap(
Student::getName,
Student::getId,
new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer entity1, Integer entity2) {
return entity1;
}
}));
We toMap
can find out by looking at the source code, as shown below:
Its third parameter is a functional interface, so we can use lamda
expressions to simplify the code.