For example, when you want to process the result extracted by joining two parent and child tables from DB for each key. You can process it as a List, but it looks better if you group it by key, right? (I personally like it because it improves readability. If there is a performance problem, I can't help it.) This time, I will try to convert to Map (key: parent table, value: child table) after batch acquisition with side-by-side List.
ER
--Department id
--Employee id --Employee name --Department id (FK)
If you get this by inner join, it will be like this. ↓
select_all.sql
select *
from Department Master
inner join employee master using department id;
Image of acquisition result (List
Department | Employee |
---|---|
Department 1 | Employee 1 |
Department 1 | Employee 2 |
Department 2 | Employee 3 |
Department 2 | Employee 4 |
Department 2 | : |
The purpose of this time is to convert this into "Map <department, List
--DemoService: Main process --DbMapper: Actually an OR mapper such as Mybatis. --DbMapperImpl: DbMapper implemented for testing. --Result: Store the result of select_all.sql --Department: Department table --Employee: Employee table
For the time being, I created two list2Map7 methods of ** Java7 ** version and ** Java8 (Stream API) **. The results should be the same for both. After all, the implementation with Stream API has a small amount of code and is easy to see. I don't really want to implement anything that has nothing to do with business logic. If you do your best, list2Map8 may be easier to see. But it seems that there will be more unreadable code besides the Service class.
DemoService.java
package com.example.demo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class DemoService {
@Autowired
DbMapper mapper;
public void execute(String[] args) {
log.info("### START ###");
// select from DB
List<Result> list = mapper.select();
//Extracted contents
list.forEach(System.out::println);
// List ⇒ LinkedHashMap
Map<Department, List<Employee>> map = list2Map8(list);
System.out.println();
//Output conversion result
for (Map.Entry<Department, List<Employee>> entry : map.entrySet()) {
System.out.println("Key:" + entry.getKey());
entry.getValue().forEach(e -> System.out.println(" Value:" + e));
}
log.info("### END ###");
}
/**
*List⇒Map conversion(java7Ver).
*
* @param list
* @return
*/
private Map<Department, List<Employee>> list2Map7(List<Result> list) {
if (list.isEmpty()) {
return Collections.emptyMap();
}
Map<Department, List<Employee>> map = new LinkedHashMap<>();
//Last key
Department prevDep = null;
List<Employee> tempList = null;
for (Result result : list) {
Department dep = result.getDepartment();
//If the key changes
if (!dep.equals(prevDep)) {
//Initialize list of values
tempList = new ArrayList<>();
//Added to the map with the values initialized(Set reference to map)
map.put(dep, tempList);
//Use this key as the previous key
prevDep = dep;
}
//Add value to tempList that references map
tempList.add(result.getEmployee());
}
return map;
}
/**
*List⇒Map conversion(java8Ver).
*
* @param list
* @return
*/
private Map<Department, List<Employee>> list2Map8(List<Result> list) {
// List(value)⇒Map(キー、value)Conversion to
Map<Department, List<Employee>> ret = list.stream()
.collect(Collectors.groupingBy(Result::getDepartment,
LinkedHashMap::new, Collectors.mapping(Result::getEmployee, Collectors.toList())));
return ret;
}
}
I am using ** LinkedHashMap ** to keep the acquisition order. It is not retained in HashMap. (Thank you for your comment and improved the conversion method.)
Actually, it feels like using Mybatis or OR mapper.
DbMapper.java
package com.example.demo;
import java.util.List;
import org.springframework.stereotype.Component;
@Component
public interface DbMapper {
List<Result> select();
}
Returns debug data.
DbMapperImpl.java
package com.example.demo;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Component;
@Component
public class DbMapperImpl implements DbMapper {
@Override
public List<Result> select() {
List<Result> list = new ArrayList<>();
list.add(getResult(1, 101));
list.add(getResult(1, 102));
list.add(getResult(2, 203));
list.add(getResult(3, 304));
list.add(getResult(3, 305));
list.add(getResult(3, 306));
return list;
}
private Result getResult(int did, int eid) {
Department department = new Department();
department.setDepartmentId(did);
department.setDepartmentName("system" + did + "Division");
Employee employee = new Employee();
employee.setEmployeeId(eid);
employee.setName("Yamada" + eid + "Ro");
employee.setDepartmentId(department.getDepartmentId());
Result result = new Result(department, employee);
return result;
}
}
The object where the SELECT result from the DB is stored first.
Result.java
package com.example.demo;
import lombok.Data;
@Data
public class Result {
private Department department;
private Employee employee;
public Result() {
}
public Result(Department department, Employee employee) {
this.department = department;
this.employee = employee;
}
}
Department master. Lombok @Data overrides hashcode and equals. The same applies to the employee master. Depending on the situation, if this actually represents one record in the table, then the only field to override is PK. In that case, create your own without using @Data. Override is required because LinkedHashMap (HashMap) is used.
Department.java
package com.example.demo;
import lombok.Data;
@Data
public class Department {
private Integer departmentId;
private String departmentName;
}
Employee master.
Employee.java
package com.example.demo;
import lombok.Data;
@Data
public class Employee {
private Integer employeeId;
private String name;
private Integer departmentId;
}
It has been properly converted to a map for each key (department).
Execution result
Result(department=Department(departmentId=1, departmentName=System Section 1), employee=Employee(employeeId=101, name=Yamada 101ro, departmentId=1))
Result(department=Department(departmentId=1, departmentName=System Section 1), employee=Employee(employeeId=102, name=102ro Yamada, departmentId=1))
Result(department=Department(departmentId=2, departmentName=System Section 2), employee=Employee(employeeId=203, name=Yamada 203ro, departmentId=2))
Result(department=Department(departmentId=3, departmentName=System Section 3), employee=Employee(employeeId=304, name=Yamada 304ro, departmentId=3))
Result(department=Department(departmentId=3, departmentName=System Section 3), employee=Employee(employeeId=305, name=Yamada 305ro, departmentId=3))
Result(department=Department(departmentId=3, departmentName=System Section 3), employee=Employee(employeeId=306, name=Yamada 306ro, departmentId=3))
Key:Department(departmentId=1, departmentName=System Section 1)
Value:Employee(employeeId=101, name=Yamada 101ro, departmentId=1)
Value:Employee(employeeId=102, name=102ro Yamada, departmentId=1)
Key:Department(departmentId=2, departmentName=System Section 2)
Value:Employee(employeeId=203, name=Yamada 203ro, departmentId=2)
Key:Department(departmentId=3, departmentName=System Section 3)
Value:Employee(employeeId=304, name=Yamada 304ro, departmentId=3)
Value:Employee(employeeId=305, name=Yamada 305ro, departmentId=3)
Value:Employee(employeeId=306, name=Yamada 306ro, departmentId=3)
Lombok is convenient, isn't it?
Recommended Posts