Given the following task. We have an Employee
and a Company
classes. Each instance of Employee
class is stored in array Employee[] employees
in the Company
class. I need a method which removes an instance of Employee
in the array Employee[] employees
by id
.
I managed to write the following code:
public class Employee {
protected final int id;
protected String name;
public Employee(int id, String name) {
this.id = id;
this.name= name;
}
public int getId() {
return id;
}
}
public class Company {
private Employee[] employees;
private int size;
private static final int defaultCapacity = 5;
public Company() {
this(defaultCapacity);
}
public Company(int capacity) {
if (capacity <= 0)
throw new RuntimeException("capacity is required");
employees = new Employee[capacity];
}
public Employee removeEmployee(int id) {
Collection<Employee> employeeList = Arrays.asList(employees)
.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
Employee[] employeeArray = employeeList.toArray(Employee[]::new);
for (int i = 0; i < size; i++) {
if(employeeArray[i].getId() == id) {
Employee removedEmployee = employees[i];
employeeList.remove(employeeArray[i]);
employees = employeeList
.stream()
.filter(Objects::nonNull)
.toArray(Employee[]::new);
return removedEmployee;
}
}
return null;
}
}
The problem is that my method public Employee removeEmployee(int id)
throws NullPointerException
if an element for removal is not found.
Question:
public Employee removeEmployee(int id)
using, for instance, Streams API and Optional in oder to get rid of NullPointerException in the method public Employee removeEmployee(int id)
?N.B.: The length of the array Employee[] employees
declared in the class Company
must be reduced after the element has been successfully removed.
There is a lot of ways to get rid of the NullPointerException here. If you want to keep using the stream API, you may want to use filter and findAny. For example, you could modify the method to the following:
public Employee removeEmployee(int id) {
Optional<Employee> employee = Arrays.stream(employees)
.filter(Objects::nonNull)
.filter(x -> x.getId() == id).
.findAny();
if(employee.isEmpty())
return null;
employees = Arrays.stream(employees).filter(x -> x != employee.get()).toArray(Employee[]::new);
return employee.get();
}
However, I would highly advise using a List or even a Map instead of an Array for employees
as this makes things way easier and faster:
public Employee removeEmployee(int id){
Optional<Employee> toRemove = employees.stream().filter(x -> x.getId() == id).findAny();
if(toRemove.isEmpty())
return null;
employees.remove(toRemove.get());
return toRemove.get();
}
Or not to use the Stream API:
public Employee removeEmployee(int id){
int idx;
for(idx = 0; idx < employees.length; idx++){
if(employees[idx] != null && employees[idx].getId() == id)
break;
}
if(idx == employees.length)
return null;
Employee value = employees[idx];
Employee[] newArr = new Employee[employees.length - 1];
// the parameters here are left as an exercise to the reader :P
System.arraycopy(newArr, ...);
System.arraycopy(newArr, ...);
employees = newArr;
return value;
}