在Java开发中,数组元素查找是基础且高频的操作,而配合合理的异常抛出逻辑,能让代码在出现非法输入或查找失败时给出明确的反馈,避免程序出现不可控的错误。实现这一逻辑需要兼顾查找效率、边界校验和异常类型的合理选择。

数组元素查找的常用实现方式
数组元素查找主要分为线性查找和二分查找两种,不同的查找方式适用不同的场景,对应的异常抛出逻辑也有差异。
线性查找实现
线性查找适用于任意数组,逻辑是从数组第一个元素开始依次遍历,直到找到目标元素或遍历完所有元素。实现时首先需要校验数组是否为空、数组长度是否为0,避免空指针异常和无效遍历。
以下是线性查找的基础实现代码:
import java.util.Objects;
public class ArraySearchUtil {
/**
* 线性查找数组中的目标元素,返回首次出现的索引
* @param arr 待查找的数组,允许为null
* @param target 目标元素
* @return 目标元素的索引,未找到时返回-1
*/
public static int linearSearch(int[] arr, int target) {
// 校验数组是否为空或长度为0
if (Objects.isNull(arr) || arr.length == 0) {
return -1;
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] == target) {
return i;
}
}
return -1;
}
}
二分查找实现
二分查找仅适用于有序数组,通过不断缩小查找区间提升效率,时间复杂度为O(logn),远优于线性查找的O(n)。实现二分查找前需要先确认数组是有序的,否则会得到错误结果。
以下是二分查找的实现代码:
public class ArraySearchUtil {
/**
* 二分查找有序数组中的目标元素
* @param sortedArr 有序数组,需保证升序排列
* @param target 目标元素
* @return 目标元素的索引,未找到时返回-1
*/
public static int binarySearch(int[] sortedArr, int target) {
if (Objects.isNull(sortedArr) || sortedArr.length == 0) {
return -1;
}
int left = 0;
int right = sortedArr.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (sortedArr[mid] == target) {
return mid;
} else if (sortedArr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
}
异常抛出的正确逻辑
查找逻辑中异常抛出的核心是明确什么场景下需要抛出异常,以及抛出什么类型的异常。通常分为使用内置异常和自定义异常两种场景。
内置异常的使用场景
对于输入参数不合法的情况,优先使用Java内置的异常类型,符合开发者的通用认知,降低理解成本。
- 如果传入的数组为null,可抛出
NullPointerException,明确提示空指针问题 - 如果要求数组不能为空但传入了空数组,可抛出
IllegalArgumentException,提示参数不合法 - 如果查找的目标元素不允许不存在,可抛出
NoSuchElementException,提示元素不存在
以下是带内置异常抛出的线性查找实现:
import java.util.NoSuchElementException;
import java.util.Objects;
public class ArraySearchUtil {
/**
* 线性查找数组中的目标元素,查找失败或参数非法时抛出异常
* @param arr 待查找的数组,不允许为null或空数组
* @param target 目标元素
* @return 目标元素的索引
* @throws NullPointerException 当arr为null时抛出
* @throws IllegalArgumentException 当arr长度为0时抛出
* @throws NoSuchElementException 当未找到目标元素时抛出
*/
public static int linearSearchWithException(int[] arr, int target) {
// 数组为null时抛出空指针异常
Objects.requireNonNull(arr, "待查找的数组不能为null");
// 数组长度为0时抛出非法参数异常
if (arr.length == 0) {
throw new IllegalArgumentException("待查找的数组不能为空数组");
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] == target) {
return i;
}
}
// 未找到目标元素时抛出无此元素异常
throw new NoSuchElementException("数组中不存在目标元素: " + target);
}
}
自定义异常的设计
如果内置异常无法准确描述业务场景,可自定义异常类型。自定义异常通常需要继承Exception或RuntimeException,前者是受检异常,需要显式捕获或声明抛出,后者是非受检异常,无需强制处理。
以下是自定义数组查找相关异常的实现:
/**
* 数组查找相关的自定义异常,继承RuntimeException,属于非受检异常
*/
public class ArraySearchException extends RuntimeException {
public ArraySearchException(String message) {
super(message);
}
public ArraySearchException(String message, Throwable cause) {
super(message, cause);
}
}
使用自定义异常的查找实现如下:
import java.util.Objects;
public class ArraySearchUtil {
/**
* 使用自定义异常实现线性查找
* @param arr 待查找的数组,不允许为null或空数组
* @param target 目标元素
* @return 目标元素的索引
* @throws ArraySearchException 当参数非法或未找到元素时抛出
*/
public static int linearSearchWithCustomException(int[] arr, int target) {
if (Objects.isNull(arr)) {
throw new ArraySearchException("待查找的数组不能为null");
}
if (arr.length == 0) {
throw new ArraySearchException("待查找的数组不能为空数组");
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] == target) {
return i;
}
}
throw new ArraySearchException("数组中不存在目标元素: " + target);
}
}
实现注意事项
在实际开发中,实现数组查找和异常抛出逻辑时需要注意以下几点:
- 异常信息要清晰明确,直接说明问题原因,比如明确提示是数组为null还是元素不存在,方便问题排查
- 根据业务需求选择异常类型,如果希望调用方必须处理异常,使用受检异常;如果是程序逻辑错误导致的异常,使用非受检异常
- 二分查找前一定要校验数组是否有序,避免返回错误结果,可添加有序校验逻辑,校验失败抛出异常
- 不要在查找逻辑中捕获异常后不做处理直接吞掉,要么处理异常,要么继续向上抛出
测试验证
编写测试用例验证查找和异常逻辑是否符合预期:
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class ArraySearchUtilTest {
@Test
public void testLinearSearchWithCustomException() {
int[] arr = {1, 2, 3, 4, 5};
// 正常查找成功
assertEquals(2, ArraySearchUtil.linearSearchWithCustomException(arr, 3));
// 数组为null时抛出异常
assertThrows(ArraySearchException.class, () -> ArraySearchUtil.linearSearchWithCustomException(null, 3));
// 未找到元素时抛出异常
assertThrows(ArraySearchException.class, () -> ArraySearchUtil.linearSearchWithCustomException(arr, 10));
}
}