java高级需要掌握的基础
JAVA基础
-
超过3层if else 的逻辑判断代码可以使用卫语句,策略模式,状态模式来实现
-
字段,类属性声明尽量不要使用is,get,set开头,容易出现错误读取
-
避免使用"等于"判断作为中端或退出条件,最好使用大于或小于区间判断条件
-
if条件里面不要执行复杂语句进行条件判断或者赋值判断,可以再外面给一个boolean值,在if里面用这个值进行判断
-
try-catch尽量不要放到for循环里去,最好能移到外面就移到外面
-
if条件判断,尽量不要使用取反!操作, 能正着取值就正着
-
try-catch块包含的内容要尽可能少
-
批量查询的公共接口,最好加一个入参保护,即最多提供多少数量的解析,防止后台爆掉
-
下列情况需要做参数校验
- 调用频次很低的方法
- 执行时间开销很大的方法
- 需要极高稳定性和可用性的方法
- 对外提供的开放接口
- 敏感权限入口
-
下列情况可以不做参数校验:
- 极有可能被循环调用的方法
- 底层调用频次比较高的方法
- 被声明private只会被自己代码调用的方法
-
标记待办事宜todo ; 标记此段代码错误不能工作FIXME; 记得及时处理掉
-
使用正则表达式时,利用预编译功能,可加快匹配速度,例如如下代码不要写在方法体里面
Pattern pattern = Pattern.compile("规则") -
不要使用apache BeanUtils 进行属性copy, 可以使用spring BeanUtils, cglib BeanCopier
-
switch入参为string时,必须做null判断在使用,否则连default都不会走
-
所有的转int,double, float, long 最好是先转成string,在进行操作,防止出现精度丢失
日期时间
- 如果是jdk8的应用,可以使用Instant代替Date类 , LocalDateTime代替Calendar类, 获取纳米级别时间用System.nanoTime()
- 日期格式化 yyyy-MM-dd HH:mm:ss, MM大写代表月份, HH大写代表24小时,其他要小写
集合处理
-
只要重写了equals,就必须重写hashCode
-
判断集合内部元素是否为空,使用isEmpty()方法,不要用size()
-
使用list,map集合进行遍历时,不能对其进行增加和删除操作,会抛出异常,应使用iterator遍历方式操作,如果并发操作,需对iterator对象、进行加锁
-
使用集合转数组的toArray(T []array),直接toArray()会出现接收值时Object[]类型, 应传入一个类型一致,长度为0的空数组进去
-
使用Collection接口的addAll()方法是,要对输入的集合参数进行NPE判断
-
Arrays.asList()方法转成的集合,不能使用它的add/remove/clear方法,否则会报错,因为转之后的集合其实是Arrays的内部类,不具备集合的方法,该方法体现的适配器,后台数据仍然是数组
-
无泛型集合给泛型集合赋值时,要注意使用instanceof进行类型判断,否则赋值时不报错,使用时会报类转换异常,例如
List a = null; List b = new ArrayList(8); b.add(1); a = b; 则使用a.任何属性操作,都会报类转换异常 -
集合泛型的写法:HashMap如果不给默认值,在高并发场景,可能会出现cpu飙升
// 后面实现类<>可以直接使用,不用写<String,String> HashMap<String,String> map = new HashMap<>(16); // 也可以全省略 ArrayList<User> user = New ArrayList(10); 注:括号里面的参数一定要给,如果不确定,默认给16, 参数值=(需要存储的元素个数 / 0.75) + 1 -
使用Map的遍历,不要遍历keyset和values, 要使用entrySet方式,可以返回k-v
-
Map集合k/v不能为空的情况,如下表格
集合类 key value super 说明 HashTable 不能为null 不能为null Dictionary 线程安全 ConcurrentHashMap 不能为null 不能为null AbstractMap 锁分段技术(jdk8:CAS) TreeMap 不能为null 允许为null AbstractMap 线程不安全 HashMap 允许为null 允许为null AbstractMap 线程不安全
POJO
- 所有的pojo类属性,必须使用包装类数据类型(防止数据库接受出现NPE异常),所有的局部变量使用基本数据类型
- 定义DO/DTO/VO 等POJO类时,不要设定任何属性的默认值
- 构造方法里面 , 禁止加入任何业务逻辑,如果有初始化,可放到init方法里面
- POJO类必须写toString()方法
- 字段,类属性声明尽量不要使用is,get,set开头,容易出现错误读取
- split方法获取的数组,需要做内容检查,防止空值,出现数组越界异常
- get,set方法内,不要增加业务逻辑,增加排查问题的难度
- 循环体内,用stringbuilder的append方法进行扩展
前后端协作
- 前后端数据列表相关接口返回,如果为空,则返回空数组[]或者集合{}, 尽量不要返回null, 或者添加code,msg值,返回成功或者失败
- 前后端交互的数据中,所有key必须都是小写字母开始的骆驼表达式,最好定义DO(数据对象)
- 后端返回给前端的int,long,double,float值,尽量使用toString(),返回给前端
- 前端传给后端的字段,尽量不要超过2048个字节,超过可能会出现异常情况,可以传关键字段,后台掉接口去查一遍(针对频次不太高的)
并发操作
-
自己定义的ThreadLocal变量,尤其在线程池场景下使用的,尽量在代理方法中使用try-finally块进行回收threadLocal.remove()
-
在使用lock.lock()时,要保证该代码与try之间不要有异常场景发生,不然容易造成无法解锁
-
simpleDateFormat是线程不安全的类,一般不要定义为static,如果要定义,请加锁,或者使用DateUtils工具类也可
-
在使用尝试机制获取锁之前,先判断是否持有锁:
Lock lock = new XxxLock(); .... boolean islocked = lock.tryLock(); if(islocked){ try{ .... }finally{ lock.unlock(); } } -
java并发包,如果主线程创建多个子线程进行处理多个逻辑,又想在处理结束后保持同步操作,需要在每个线程退出前调用coundDown方法,主线程使用CountDownLatch进行异步转同步操作,具体使用方法自行百度
-
volatile 解决多线程内存不可见问题, 如果是count++操作,推荐使用
AtomicInteger count = new AtomicInteger(); count.addAndGet(1); // 如果是jdk8,推荐使用LongAdder对象,比AtomicLong性能更好
异常日志
- 错误码5位: 来源分3类:例如:A/B/C ,A代表来源于用户,B代表来源于业务逻辑,C代表来源于第三方系统, 后面4位数字,从0001到9999,可以定义为不同的错误类型常亮或者枚举
- finally里面不要有return,否则会直接放弃掉try的return; 流程是执行完try,并不会直接返回,而是执行完finally,然后在返回
- 防止NPE,可以使用jdk8的Optional类来做,具体自行百度
- String.format可以用来做占位符输出,还有logger.debug等也有对应的占位符写法
- 对于dao层出现异常,推荐自定义异常,命名用DAOException , Service层出现异常,用ServiceException 异常类处理或者抛出
数据库
- 单元测试方法之间是独立的,不能相互引用
- 数据库表名,字段名,尽量使用小写字母表示,不要使用大写字母
- 小数类型是decimal, 禁止使用float,double, 会出现精度丢失
- 业务上具有唯一特性的字段,即使建立了组合索引,也必须建成唯一索引, 唯一索引insert速度可以忽略不计,但是提高查询速度很可观,而且没有唯一索引,必然会有脏数据产生
- 查询全表,适当每次查所有数据集合时做好分页
- 页面搜索严禁左模糊或者全模糊,因为索引文件具有B-Tree的最左前缀匹配特性,如果左边的值不确定,那么无法使用此索引
- where最先筛选出元素的条件放到前面,记得索引优先,匹配度最高的在最左边
- 不要使用count(列名),count(1) 来代替count(* ) , count(* ) 会统计null行,其他的可能会忽略统计; count(distinct col1)计算该列除null的不重复行数, count(distinct col1,col2) 如果其中有一列全是null, 那么另一列即使有不同的值,也返回0
- 使用sum时要注意结果空值判断,可使用如下方式:select IFNULL(SUM(col1), 0) from table;
- 使用ISNULL(col1) 来判断数据库null值比较高效而且简洁
- 禁止使用存储过程,难调试,难扩展,更没有移植性
- sql语句中表别名必须加, 防止后面关联sql查询出现相同列,导致异常
- in操作能不用就不用,即使要用,也要评估in后面的数据不能超过1000个
- truncate table 不要用,因为不会触发事务,容易出现问题
- POJO类的布尔属性不能加is , 而数据库boolean字段必须加is_ , 因为强制要求,必须在xml中做resultMap的映射,时字段与DO类解耦,方便维护
- 尽量不要使用HashMap和Hashtable作为结果集直接返回,容易出现字段类型转换错误, 推荐使用DO
- mybatis 中的 isNotEmpty表示不为空并且不为null时执行, 而isNotNull表示不为null值时执行
工程结构
- 分层领域模型:
- DO : 与数据库表机构一一对应,DAO层向上传输的数据对象
- DTO : 数据传输对象,service层之间传输的数据对象
- BO : 业务对象,由service层输出的封装业务逻辑的对象
- Query :数据查询对象,各层接收上层的查询请求, 禁止使用Map类来传输
- VO : 显示层对象,通常是web向模板渲染传输的对象
开头:
1.介绍下最近这个项目,项目背景,上下游关系,主要功能,应用场景,受众人群,用户量,
2.你在项目中负责哪些模块
3.掌握的后端java框架技术
java基础:
1.什么叫拆箱,装箱? 装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型
2.jdk和jre的分工是什么?
3.遇到过内存溢出这种情况么? 一般哪些情况容易出现?怎么解决的?开发过程中怎么避免?
4.通过反射得到一个类的对象,有几种方法?
5.如何实现HashMap线程安全?
1.HashTable
Map<String, String> hashtable = new Hashtable<>();
2.ConcurrentHashMap
Map<String, String> concurrentHashMap = new ConcurrentHashMap<>();
3.Synchronized Map
Map<String, String> synchronizedHashMap = Collections.synchronizedMap(new HashMap<String, String>());
6.java的堆和栈分别是什么? 堆是公共的内存区域,栈是当前线程运行使用的内存区域
7.有没有遇到过sql注入,用哪些手段可以解决这个问题?
线程&高并发:
1.线程池用过么?都有什么参数?
2.线程和进程有什么区别?
2.多线程实现有几种方式?thread的start()和run()方法有什么区别?
2.ThreadLocal 有用过么? 用在哪些地方?
3.java的 Volitile变量 有用过么? 这么用的? 为什么要用?
4.如果线程运行时发生异常会怎么走?
spring:
1.Spring bean的生命周期?默认创建是单例模式,如果不想单例怎么办? 实例化bean——》依赖注入——》处理Aware接口(3种),实现不同Aware接口的传入不同的信息——》初始化bean(两种,前置和后置)——》destroy(); scope="prototype"
2. spring Aop的实现原理?
3.springBoot的启动流程? 首先从SpringApplication的初始化模块,配置一些基本的环境变量、资源、构造器、监听器,第二部分实现了应用具体的启动方案,包括启动流程的监听模块、加载配置环境模块、及核心的创建上下文环境模块,第三部分是自动化配置核心模块
4.spring如何实现多数据源配置? +mybatis配合,如何做到读写分离?
sql:
1.那些情况下会发生明明创建了索引,但是执行的时候并没有通过索引呢?
2.一般会在什么情况下加索引?最起码列出来3条?
3.聚集索引和非聚集索引有什么区别? 分别在什么情况下使用?
mybatis:
1.mybatis mapper方法能重载么?dao层呢?
2.mapper接口的工作原理是什么?
3.mybatis批量新增,可以返回主键列表么?
4.mybatis插件有哪几个接口可以实现? ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口的插件
5.Mybatis是如何进行分页的?分页插件的原理是什么?

浙公网安备 33010602011771号