一、Stream 流熟悉吗?说一下常用的 API?
熟悉,Stream 是 Java8 对集合 / 数组的流式处理工具,核心特点:中间操作惰性执行,只有调用终止操作才会触发计算,大大简化集合遍历 / 处理代码,项目中高频使用。
- 创建流(最常用):
集合.stream()、集合.parallelStream()(并行流); - 中间操作(链式调用,返回新流,不改变原数据):
filter()(条件过滤)、map()(元素映射转换)、distinct()(去重)、sorted()(排序)、limit()(截取前 N 条)、skip()(跳过前 N 条)、flatMap()(扁平化拆分集合); - 终止操作(结束流,返回最终结果):
forEach()(遍历消费)、collect()(核心,转集合:Collectors.toList ()/toSet ()/toMap ())、count()(统计数量)、anyMatch()/allMatch()(条件匹配)、findAny()/findFirst()(获取元素)、max()/min()(最值)。
二、你们项目是怎么处理异常的?你说一下怎么实现全局自定义异常处理器?
项目整体异常处理方案
- 自定义业务异常类(比如 BizException):继承 RuntimeException,封装错误码 + 错误信息,项目中业务侧的异常全部手动抛自定义异常(比如参数校验失败、业务规则不满足、数据不存在);
- 运行时异常(空指针、数组越界等):不手动捕获,交给全局处理器统一兜底;
- 系统异常(数据库、第三方调用失败):针对性捕获,抛自定义异常后走全局处理;
- 核心原则:不滥用 try-catch,业务代码中只捕获需要特殊处理的异常,通用异常全部由全局处理器统一处理,保证业务代码整洁。
三、什么是 AOP?说一下实现 aop 的步骤?有哪些通知?项目中哪里用到了 aop?
1. 什么是 AOP?
AOP 是面向切面编程,Spring 核心特性之一,核心思想是:解耦,将非业务的「横切逻辑」抽离出来,不侵入核心业务代码。简单说:把项目中重复的、和业务无关的逻辑(日志、权限、事务、耗时统计),统一提取成「切面」,动态植入到目标方法的执行流程中,业务代码只关注自身逻辑,不用写冗余代码。
2. SpringBoot 实现 AOP 的步骤
- 引入依赖:spring-boot-starter-aop(核心依赖,无需额外配置);
- 创建切面类,类上添加两个注解:
@Aspect+@Component(交给 Spring 容器管理,标记为切面); - 定义切入点:用
@Pointcut("execution(表达式)")声明要拦截的方法(比如:拦截 service 层所有方法、拦截指定包下的所有 controller 接口); - 编写通知方法:在方法上添加通知注解,实现具体的横切逻辑,完成。
3. AOP 有哪些通知?
共 5 种核心通知,完整执行顺序(正常情况) :前置通知 → 目标方法执行 → 返回通知 → 后置通知异常情况执行顺序:前置通知 → 目标方法执行 → 异常通知 → 后置通知
@Before前置通知:目标方法执行之前执行;@AfterReturning返回通知:目标方法正常执行完成后执行,能拿到方法返回值;@AfterThrowing异常通知:目标方法抛出异常时执行,能拿到异常信息;@After后置通知(最终通知):无论目标方法成功 / 失败,都会执行,类似 finally;@Around环绕通知(最重要、功能最强):包裹整个目标方法,能控制目标方法是否执行、执行前后做增强、修改返回值,项目中用的最多的通知类型。
4. 项目中哪里用到了 AOP?
项目中实际落地场景很多,核心 3 个高频使用:
- 接口日志统一记录:拦截所有 Controller 接口,记录「请求参数、请求地址、响应结果、请求耗时」,不用每个接口手动写日志;
- 接口统一权限校验:拦截需要鉴权的接口,前置校验 token 有效性、用户权限,通过则放行,不通过则抛异常,统一做权限拦截;
- 方法执行耗时统计:拦截核心 Service 层方法,统计接口 / 方法的执行时间,排查性能瓶颈;补充:事务管理(@Transactional 底层就是 AOP 实现)、接口防重复提交、全局异常兜底增强。
四、最后你有什么想问我们的?
版本一(万能安全,所有公司适配,首选)
- 想了解下咱们这个岗位的项目,目前的核心技术难点或者业务痛点是什么?
- 咱们团队的技术栈后续有没有迭代规划?比如是否会引入新的技术组件优化现有架构?
版本二(进阶走心,更显主动,适合技术型公司)
- 这个岗位入职后,主要负责的业务模块和核心工作内容是什么?
- 咱们团队对于开发人员的成长,有没有对应的技术沉淀或者内部分享机制?