提问人:Evgeniy 提问时间:11/23/2022 更新时间:11/23/2022 访问量:137
从数组中删除元素时如何摆脱 NullPointerException?[复制]
How to get rid of NullPointerException when removing elements from array? [duplicate]
问:
给定以下任务。我们有一个和一个类。类的每个实例都存储在类的数组中。我需要一种方法,通过以下方式删除数组中的实例。Employee
Company
Employee
Employee[] employees
Company
Employee
Employee[] employees
id
我设法编写了以下代码:
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;
}
}
问题是,如果找不到要删除的元素,我的方法就会抛出。public Employee removeEmployee(int id)
NullPointerException
问题:
- 例如,如何使用 Streams API 和 Optional 重写方法以摆脱方法中的 NullPointerException?
public Employee removeEmployee(int id)
public Employee removeEmployee(int id)
注意:成功删除元素后,必须减少类中声明的数组的长度。Employee[] employees
Company
答:
这里有很多方法可以摆脱 NullPointerException。 如果要继续使用流 API,可能需要使用 filter 和 findAny。 例如,可以将该方法修改为以下内容:
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();
}
但是,我强烈建议使用 List 甚至 Map 而不是 Array,因为这会使事情变得更容易、更快捷:employees
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();
}
或者不使用 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;
}
评论
成功删除元素后,必须减少在类中声明的数组 employees 的长度。
Employee[]
Company
在这种情况下,Streams 不会给你带来很多好处。
您应该做的是找到具有目标的元素,如果存在这样的元素,则通过复制除找到的元素之外的所有元素,在内存中分配一个长度较小的新数组,并分配对新数组的引用。id
1
employees
为了减少长度,我们可以利用 .首先复制目标之前的元素,然后复制目标之后的元素。System.arraycopy()
这就是普通的基于索引的 -loop 的样子。for
public Employee removeEmployee(int id) {
Employee result = null;
int index = -1;
for (int i = 0; i < employees.length; i++) {
if (employees[i] != null && employees[i].getId() == id) {
result = employees[i];
employees[i] = null;
break;
}
}
if (result != null) {
reduceLength(index);
}
return result;
}
public void reduceLength(int i) {
Employee[] newEmployees = new Employee[employees.length - 1];
System.arraycopy(employees, 0, newEmployees, 0, i);
System.arraycopy(employees, i + 1, newEmployees, i, employees.length - (i + 1));
employees = newEmployees;
}
If you want to do weird stuff and use Stream API and Optional at all costs, here how it can be done (but I would recommend to stick with the code above):
public Optional<Employee> removeEmployee(int id) {
Optional<Integer> index = IntStream.range(0, employees.length)
.filter(i -> employees[i] != null)
.filter(i -> employees[i].getId() == id)
.boxed() // otherwise will get OptionalInt which lacks map() method
.findFirst();
Optional<Employee> result = index.map(i -> employees[i]);
index.ifPresent(this::reduceLength);
return result;
}
Considering it's homework and constraints mentioned, i believe you are supposed to do all the work using the array only.
I'll provide some guideline and leave the actual implementation to you:
public class Company {
private Employee[] employees;
private int size;
public Employee removeEmployee(int id) {
int index = -1;
//find the index of employee with required id, you have mostly done that
if (index == -1) {
return null;
}
//save found employee to variable
//remove from array
//shift array to the left
//do not forget to use and reassign size variable where appropriate
}
//some extra
public void addEmployee(Employee employee) {
//resize array if necessary
//add employee at correct position in array
//do not forget to use and reassign size variable where appropriate
}
}
If you get stuck, you can look at the class, your task is basically a simplified version of it. I strongly advise you to use this as source of inspiration only and not to copy the source code!!!ArrayList
上一个:避免向数组添加 null 值
下一个:填充字符串数组时检查重复项
评论
List<Employee>
List
removeEmployee
array
array