最近写java代码学到的一些point,主要是我在公司实习的时候,自己碰到的一些问题,总结一下。会持续更新。
1.知识点
1.解决dao层频繁访问数据库问题
问题:平常写java的都经常会有功能点:service.getElementByID(id),以前我在写的时候,比如从前端接收到对象的list-》根据list中某个对象的id查询数据库的某张表的其他属性name-》第一反应是直接for循环遍历获取对象id,然后根据id调用service中的getnameByID方法。
这个做法实际上是可以的,但是如果数据量很大的情况下,多次访问数据库IO消耗巨大。
解决:先select * from 数据中的某张表A,获取全部需要的数据,然后把你需要查找的一列name与ID一一对应存入map。然后for循环list中的id时,直接从map中查找。
这样操作的话就相当于只访问了一次数据库。同时因为map的get操作的时间复杂度在理想的情况下为O(1)。
代码:
//定义map list为一次从数据库获取所有数据
Map<String,Object> map = new HashMap<>();
List<Object> lists = service.findAll();
if(lists!=null && !lists.isEmpty()){
//将list中所有数据存入map
lists.forEach(bean->{
map.put(bean.getID(),bean);
});
}
//在操作的时候,如果map中存在对应的key,直接get
if(map.containsKey(bean.getID()) ){
System.out.println(bean.getName());
}
2.异常捕捉
2.0 异常关键词
异常关键字
1:try catch
try catch是这之间所包含的代码如果出现异常时捕获他,并进行处理的,如果代码之间有错误,不会影响程序继续执行下去,程序会继续往后执行。
2:throw
是在程序中明确抛出引发的异常,比如throw new Exception();
3:throws
表明方法可能会引发异常,在方法内部并不处理这个异常,想要得到异常的话,调用者使用try catch语句即可得到
4:finally
不管有没有异常程序段中都会被执行的代码
2.1 for循环异常捕捉
问题:其实我们在学校自己做项目的时候,几乎不会去主动catch异常,很多异常情况都不能很规范的考虑到。而在公司中业务则要求:某一个块碰到什么问题,一定要以日志的形式打印出来,碰到什么异常捕获并返回jsonMap说明异常情况。
解决:养成异常捕获的习惯。
站在用户的角度去思考业务,而不是站在代码的角度。
我们在写一个业务的时候, 不要理所当然的觉得按照我们的逻辑是不会出现问题的,但是用户是小白,他们在操作的时候不完全按照我们的逻辑。
代码:
private Map<String,Object> getRes(String A) {
Map<String, Object> jsonMap = new HashMap<>();
try {
List<Object> a = service.getByA(A);//这个方法可能抛异常
Map<String, Object> map = new HashMap<>();
for(Object p:a){
if(StringUtils.isBlank(p.getBootStatus())){
continue;//过滤异常情况,避免抛异常
}
if(StringUtils.isNotBlank(p.getId())&&StringUtils.isNotBlank(p.getIp())){
map.put(p.getName(),p.getIp());
}
}
jsonMap.put("success", true);
jsonMap.put("data",map);
} catch (Exception e) {
jsonMap.put("success", false);
jsonMap.put("errorMsg", "A = " + A + " 访问 api 发生异常!");
log.error("exception:{} ",e);
}
return jsonMap;
}
备注:对于异常的处理,很多公司都会比较重视。
- 某次面试,被面试官问:用过或者遇到过哪些异常?
对于我来说,常见的异常有NullPointerException,ArrayIndexOutOfBoundsException,SQLException,IOException。
2.2 新建一个异常类
偶然看到一段代码是自己自定义的异常,不明白为什么需要自己定义异常并且抛异常?所以去查阅了一些资料。
为什么要自定义异常:
大的项目业务线比较多,不同功能模块的异常类型不一样,如果不自定义的区分的话,对于捕获异常来就没有区别性。所有一般业务中不同场景抛不同的异常,便于统一捕捉并且根据类型做进一步的处理。 但是自定义异常一般会增加工作量,需要自己权衡是否自定义异常类。
如何自定义异常类:
//1.自定义异常类:继承RuntimeException(运行时异常) 或 Exception
public class MyException extends Exception {
private static final long serialVersionUID = 1L;
// 提供无参数的构造方法
public MyException() {
}
// 提供一个有参数的构造方法,可自动生成
public MyException(String message) {
super(message);// 把参数传递给Throwable的带String参数的构造方法
}
}
//2.抛异常类
public class CheckScore {
// 检查分数合法性的方法check() 如果定义的是运行时异常就不用抛异常了
public void check(int score) throws MyException {// 抛出自己的异常类
if (score > 120 || score < 0) {
// 分数不合法时抛出异常
throw new MyException("分数不合法,分数应该是0--120之间");// new一个自己的异常类
} else {
System.out.println("分数合法,你的分数是" + score);
}
}
}
//3.捕获异常
import java.util.Scanner;
/*
* 自定义的异常测试类
*/
public class Student {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int score = sc.nextInt();
CheckScore check = new CheckScore();
try {
check.check(score);
} catch (MyException e) {// 用自己的异常类来捕获异常
e.printStackTrace();
}
}
}
备注: 异常分类方便捕捉不同的异常类型,并进行对应的操作。在稍微复杂的业务系统中,仅仅使用Java自身的异常类是不够的,比如常见的NPE/IAE等。
- 有时候需要对参数进行各种检查,NPE不足以清晰的说明异常的具体内容。比如有多个参数,对每个参数进行自定义的校验规则,可以通过IAE(message: String)来让调试过程更加友好。
- 自定义参数,比如数据解析异常,可能中间多处可能抛出,这里可以定义一个MyParseException,针对此类异常通常使用相同的善后操作。
- 自定义异常可以定义层次结构,即某个业务系统中的所有异常统一顶一个根类,然后再定义一些子类异常,分类进行针对性的操作。比如定义一个MyRootException,然后对网络通信解析的异常MyParseException,对数据访问的异常MyDataException等,这些异常都代表了不同的类型,操作句柄也都是不一样的。
参考链接:www.cnblogs.com/yanggb/p/10…
3.@Value注解使用
作用:读取配置文件的属性
注解方式:
定义(map类型):
property.key = {"A":"a","B":"b"}
使用:
@Value("#{${property.key}}")
private Map<String, String> propertykey;
propertykey.get(A);
4.controller接收list参数的时候需要添加@RequestBody注解
5.mybatis-generator生成bean的时候对于mysql中text字段的特殊处理
在generatorconfig中添加
<columnOverride column="your column" jdbcType="VARCHAR" />
即如下:
<table schema="XXX" tableName="table" >
<columnOverride column="your text column" jdbcType="VARCHAR" />
</table>
6.logger
打印错误的时候,最好包括:类名,方法名,输入的参数,错误代码,错误信息等
logger.info("classname.method input:{}, error code:{},message:{},request ID:{}",A,B,C,D);
7.后端String转化成Map,返回前端并以json格式显示
//后端拿到的是String数据,如input-String,但前端需以json的格式显示。
Gson gson = new Gson();
Map<String,Object> map = new HashMap<String,Object>();
map = gson.fromJson("input-String",map.getClass());
jsonMap.put("data",map);
eg:
1.input-String
"{\"24\":\"公务员补收\",\"25\":\"特殊手工补收\",\"10\":\"正常应缴\",\"32\":\"一次性清算\",\"20\":\"补收\",\"21\":\"离休人员补收\"}"
2.map
{
"24": "公务员补收",
"25": "特殊手工补收",
"10": "正常应缴",
"32": "一次性清算",
"20": "补收",
"21": "离休人员补收"
}
//返回的数据 直接使用JSON.stringify(data,null,2)显示
if(response.success){
var data = response.data;
var myJSON = JSON.stringify(data,null,2);
console.log(myJSON);
$("#"+domID2).val(myJSON);//在显示框中显示
} else {
error_messages("msg", null, response.message);
}
//JSON.stringify(value, replacer, space) value是对象 按两个字符缩进
8.SSH 堡垒机 线上查看日志
在公司实习,一般项目有三种环境,分别为dev:本地开发环境 test:线上的测试环境 online:线上真实环境。
- dev环境一般就是每个人的本地环境,dev,test,online是统一的登录接口,大概是为了方便管理,不过我还不清楚为什么dev环境也需要公司内网才能运行。
- test和online一般都是在服务器上,一般的工作流程是本地功能实现测试完成之后,会推送到测试环境,再测试一遍,但是这个时候如果出现问题,是不能调试的,如果想要进测试环境的话,是不能直接ssh 测试环境的服务器,而是通过堡垒机。
- 每次登录线上的机器都要ssh xxxxip到堡垒机上,然后再到堡垒机上选择你项目组中的测试环境ip连接。
//查看线上日志,实时打印
tail -F XXX.log
9.Linux查看某进程是否运行并杀掉
ps -ef | grep tomcat
kill -9 pid
10.解决idea闪退(idea如何修改内存)
20191220:今天早上突然idea闪退,多次打开皆没过多久就闪退,并且打开任务管理器发现每次idea一打开CPU直逼100%,想到我可是24G的运行内存,觉得很好奇。
-Xms128m
-Xmx2048m
-XX:MaxPermSize=350m
-XX:ReservedCodeCacheSize=240m
-XX:+UseConcMarkSweepGC
-XX:SoftRefLRUPolicyMSPerMB=50
-ea
-Dsun.io.useCanonCaches=false
-Djava.net.preferIPv4Stack=true
-XX:+HeapDumpOnOutOfMemoryError
-XX:-OmitStackTraceInFastThrow
设置之后idea仍然闪退,后面发现idea的启动文件根据你装的idea是32位还是64位而加载不同的启动文件。
-server
-Xms128m
-Xmx512m
-XX:MaxPermSize=250m
-XX:ReservedCodeCacheSize=240m
-XX:+UseConcMarkSweepGC
-XX:SoftRefLRUPolicyMSPerMB=50
-ea
-Dsun.io.useCanonCaches=false
-Djava.net.preferIPv4Stack=true
-XX:+HeapDumpOnOutOfMemoryError
-XX:-OmitStackTraceInFastThrow
参数说明
-XX:ParallelGCThreads= 的值修改为你cpu的核数.
-Xms512m 设置初时的内存大小,提高Java程序的启动速度
-Xmx750m 设置最大内存数,提高该值,可以减少内存Garage收集的频率,提高程序性能
-Xverify:none 关闭Java字节码验证,从而加快了类装入的速度,并使得在仅为验证目的而启动的过程中无需装入类,缩短了启动时间
-XX:+UseParNewGC 使用并行收集算法
-server 控制内存garage方式,这样你无需在花一到两分钟等待内存garage的收集
-Dsun.awt.keepWorkingSetOnMinimize=true 可以让IDEA最小化到任务栏时依然保持以占有的内存,当你重新回到IDEA,能够被快速显示,而不是由灰白的界面逐渐显现整个界面,加快回复到原界面的速度。
问题:事实证明idea内存不是设置的越大越好。为什么我的电脑设置的1024M太大会闪退而需要设置为512M,而有的用户设置的750太小会闪退而需要设置1024M甚至更多???
参考:www.jianshu.com/p/5600ed195…
11.gc overhead limit exceed
这个问题是我在推包到虚机上的时候发生的,参考:juejin.cn/post/684490…
看到这个问题的时候查阅了文档发现是因为:超过了GC的开销限制,导致内存溢出。也就是说超过98%的时间用来做GC,并且回收了不到2%的堆内存时会抛出此异常。
查阅百度的时候:
修改bin目录下catalina.sh文件
在cygwin=false之上
添加以下语句
JAVA_OPTS="-Xms1024m -Xmx4096m -Xss1024K -XX:PermSize=512m -XX:MaxPermSize=2048m"
其中-xms为jvm初始化堆的大小,-xmx为jvm堆的最大值
2. window 下调整tomcat的内存设置
修改bin目录下catalina.bat文件@echo off下追加
set JAVA_OPTS=-XX:PermSize=64M -XX:MaxPermSize=128m -Xms512m -Xmx1024m
3.eclipse下修改外置tomcat的内存设置
open launch configuration=>arguments=>vm arguments
追加-Xms1024M -Xmx4096M -XX:PermSize=512m -XX:MaxPermSize=2048m
————————————————
版权声明:本文为CSDN博主「liny丶」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_23154263/article/details/79503903
这个部分能够解决大部分问题,所以收集了。但是没有解决我的问题。看了很久才发现我的问题是因为我开了多个Tomcat进程。kill重启Tomcat即可。哈哈哈我是个逗比。但是解决这个问题中还是学到了不少。
12.git基于本分支创新新分支
1.切换到当前分支
git checkout develop //进入develop分支
2.根据当前分支新建一个分支
git checkout -b fromdevelop //以develop为源创建本地分支fromdevelop
3.推送到远程分支
git push origin fromdevelop //将本地fromdevelop分支作为远程fromdevelop分支
13.idea remote Tomcat
14.13位时间戳转化为Date格式
public static Date numberDateFormatToDate(String timestamp,String simpleDateFormatType){
SimpleDateFormat sdf = new SimpleDateFormat(simpleDateFormatType);//要转换的时间格式
Date date = null;
try {
if (timestamp.length() == 13){
date = sdf.parse(sdf.format(Long.parseLong(timestamp)));
}else{
date = sdf.parse(sdf.format(Long.parseLong(timestamp)*1000));
}
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
15.US格式时间转化成Date
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(df.format(date));
t.setCreateDate(date);
try {
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
Date d=sdf.parse(td.get("CreationDate").toString());
SimpleDateFormat sdf2=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
t.setBucketCreationDate(sdf2.parse(sdf2.format(d)));
} catch (ParseException e) {
e.printStackTrace();
}
16.格林威治时间转化Date
private Date StringToDate(String date) {
Date d = null;
try {
date = date.replace("Z", "").replace("T", " ");
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
d = format.parse(date);
} catch (ParseException e) {
e.printStackTrace();
}
return d;
}
17.js base64加密
window.btoa('china is so nb') // 编码
"Y2hpbmEgaXMgc28gbmI="
window.atob("Y2hpbmEgaXMgc28gbmI=") // 解码
"china is so nb"
2.开发工具
1.mybatis-generator
这是一款逆向工程工具,针对数据库表自动生成mybatis执行所需要的代码,一般有三种用法:命令行,eclipse插件,maven插件。比较通用的就是maven插件。
具体使用方法比较常见:
(1)在pom.xml导入依赖的包
(2)generatorConfig.xml文件
(3)IDEA中直接点击插件执行
至此,其中的pojo dao mapper xml等文件都会自动生成。
想起以前搭建框架的时候,每次都是手动创建
2.postman测试工具
上手还是很快的,对于接口测试非常有用
3.IDEA debug
debug的一方面是为了调试代码,找到问题。另一方面也可以帮助我们理解新代码。
作为一个实习生,刚到公司,每次写一个业务之前,一定是要熟悉别人的代码。而熟悉代码最快路径第一步是找一个接口测试这个功能点,第二步是在代码中打断点调试,看每个函数调用的返回值的变化。
1.断点尽量打在有返回值的语句、if判定条件语句
2.F9跳转断点,快捷。代码修改之后,可重复发送请求继续调试
3.80%的问题都可以用debug解决
4.热部署Jrebel
这是一个非常实用的后端项目热部署插件。因为idea没有集成热部署工具,所以只能安装插件使用,可以让你效率加倍。众所周知,Spring项目如果很大的话,每修改一点代码就要重启Tomcat,耗时长。
n.总结
- 公司的大佬还是很多的,某天看到小组老大写的代码,惊叹:这就是架构师和程序员的区别啊!! 好好学习。