日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java优化代码常见套路

發布時間:2023/12/14 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java优化代码常见套路 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

    • 程序員的痛點(爛代碼)
    • 該如何優化代碼
    • 前臺后臺兩次md5加鹽加密
    • JSR303和全局異常處理
    • Redis通用的key生成策略和通用的RedisService方法
    • 程序猿的必讀書籍

程序員的痛點(爛代碼)

每次做完項目之后,自己想重新回顧一下以前寫的代碼,整理出一些東西,卻發現如同看天書一般,頭暈眼花,完全感覺不像自己的寫的代碼,辣眼睛,猶如下圖

所以為了愛護本人的眼睛,所以覺得很有必要整理一下一些優化代碼的套路…

首先說一個最重要的優化原則:代碼優化是你覺得你代碼很繁瑣、閱讀性很差的時候一定要馬上優化,立刻馬上,不管你現在有多忙,每天優化才叫重構,每年優化那叫重寫

這個原則為什么重要?因為很多程序員會在寫代碼的時候說「先不優化了,等不忙的時候再優化」,然后……就沒有然后了,我也是這樣,所以就導致了大量撈比代碼的產生

該如何優化代碼

1、邏輯復雜的業務代碼一定要有注釋(可能你寫的是爽了,后面維護你代碼的人可能會想往你頭上暴扣)

2、首先是變量名、方法名這些,命名一定要規范,千萬別出現aa、bb這種命名,然后我們可以對我們的一些狀態變量進行集中管理
這個什么意思呢,比如我們在項目中一個訂單的狀態,0代碼已下單、1代表已付款、2代表交易中等等…這一大堆的狀態代表數據。
可能前期我們寫的時候印象很深刻,萬一后期你要改動,又或者需求有變動?你確定你的一堆狀態數字還記得嗎

所以我們在項目開始初期就可以寫一個工具類,來專門管理我們狀態結果
比如

package com.javaxl.miaosha_02.result;public class CodeMsg {private int code;private String msg;//通用的錯誤碼public static CodeMsg SUCCESS = new CodeMsg(0, "success");public static CodeMsg SERVER_ERROR = new CodeMsg(500100, "服務端異常");public static CodeMsg BIND_ERROR = new CodeMsg(500101, "參數校驗異常:%s");//登錄模塊 5002XXpublic static CodeMsg SESSION_ERROR = new CodeMsg(500210, "Session不存在或者已經失效");public static CodeMsg PASSWORD_EMPTY = new CodeMsg(500211, "登錄密碼不能為空");public static CodeMsg MOBILE_EMPTY = new CodeMsg(500212, "手機號不能為空");public static CodeMsg MOBILE_ERROR = new CodeMsg(500213, "手機號格式錯誤");public static CodeMsg MOBILE_NOT_EXIST = new CodeMsg(500214, "手機號不存在");public static CodeMsg PASSWORD_ERROR = new CodeMsg(500215, "密碼錯誤");//訂單模塊 5004XXpublic static CodeMsg ORDER_NOT_EXIST = new CodeMsg(500400, "訂單不存在");//秒殺模塊 5005XXpublic static CodeMsg MIAO_SHA_OVER = new CodeMsg(500500, "商品已經秒殺完畢");public static CodeMsg REPEATE_MIAOSHA = new CodeMsg(500501, "不能重復秒殺");private CodeMsg( ) {}private CodeMsg( int code,String msg ) {this.code = code;this.msg = msg;}public int getCode() {return code;}public void setCode(int code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public CodeMsg fillArgs(Object... args) {int code = this.code;String message = String.format(this.msg, args);return new CodeMsg(code, message);}@Overridepublic String toString() {return "CodeMsg [code=" + code + ", msg=" + msg + "]";} }

在實際開發中如果項目比較大,甚至可以分模塊來管理,每一個模塊都專門寫一個工具類來管理你的狀態代碼

3、盡量避免重復代碼
當你發現某些代碼重復出現的次數一多,你就應該有想法把它們抽取出來進行優化了

比如我們在做前后端分離項目的時候,后端每一個方法都需要返回固定的Json格式,以前我們是這樣干的,我們可能會封裝一個JSON格式的工具類JsonData,里面有3個參數,第一個是返回碼、第二個是消息提示、第三個是結果集
比如我下面的登錄方法

public JsonData login(Staff staff){JsonData jsonData = null;Staff login = staffService.login(staff);if(login != null){//登錄成功jsonData = new JsonData(1,"歡迎管理員"+staff.getStaffName()+"",login);}else{jsonData = new JsonData(0,"用戶名或密碼錯誤",login);}return jsonData;}

然后我們發現我們每次都要重復寫我們的狀態碼、消息提示這些東西,那么我們就可以想辦法優化一下了,在固定的地方寫好,我們調用就好了,我們用泛型T指定類型,成功就返回成功的類型,失敗了返回失敗的類型

package com.p2p.p2pstaff.config;public class Result<T> {private int code;private String msg;private T data;/*** 成功時候的調用* */public static <T> Result<T> success(T data){return new Result<T>(data);}/*** 失敗時候的調用* */public static <T> Result<T> error(CodeMsg codeMsg){return new Result<T>(codeMsg);}private Result(T data) {this.data = data;}private Result(int code, String msg) {this.code = code;this.msg = msg;}private Result(CodeMsg codeMsg) {if(codeMsg != null) {this.code = codeMsg.getCode();this.msg = codeMsg.getMsg();}}public int getCode() {return code;}public void setCode(int code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public T getData() {return data;}public void setData(T data) {this.data = data;} }

我們就在全局狀態管理類中添加我們的失敗狀態

//staffpublic static CodeMsg STAFF_FAIL = new CodeMsg(0,"登錄失敗");

然后最終優化后的代碼

public Result<Staff> login(Staff staff){Staff login = staffService.login(staff);if(login != null){//登錄成功return Result.success(login);} else{return Result.error(CodeMsg.STAFF_FAIL);}}

前臺后臺兩次md5加鹽加密

后臺md5加密相比大家是耳孰能詳,我們的shiro等很多權限框架都用到了這一點,而在后臺加密依然可能存在密碼被截取的可能性。

想象你的密碼在被加密前就已經被抓取到了那么加密還有什么用呢?也就是截取我們表單提交的內容,這個是有很多辦法能夠實現的,比如我們利用抓包工具等等,所以說密碼一樣存在泄漏的可能。
所以我們就有了在前臺就先加密一次然后再提交到后臺,這樣就算截取到了也是我們加密后的密碼了

所以我們需要在登錄前進行密碼處理

//獲取我們輸入的密碼var inputPass = $("#password").val();/* var g_passsword_salt="1a2b3c4d" */var salt = g_passsword_salt;var str = ""+salt.charAt(0)+salt.charAt(2) + inputPass +salt.charAt(5) + salt.charAt(4);var password = md5(str);

前臺加密完后進入后臺,用我們加密過的密碼進行二次加密,我們兩次加密的密碼都要存入數據庫的,不然我們登錄是無法驗證的

后臺取出我們需要認證的鹽,然后用我們的shiro去認證密碼,這個工具類就和我們以前shiro使用的驗證的是一樣的

/*** 進行密碼驗證** @param credentials 未加密的密碼* @param salt 鹽* @param encryptCredentials 加密后的密碼* @return*/public static boolean checkCredentials(String credentials, String salt, String encryptCredentials) {return encryptCredentials.equals(createCredentials(credentials, salt));} public String login(HttpServletResponse response, LoginVo loginVo) {if(loginVo == null) {throw new GlobalException(CodeMsg.SERVER_ERROR);}String mobile = loginVo.getMobile();String formPass = loginVo.getPassword();//判斷手機號是否存在MiaoshaUser user = getById(Long.parseLong(mobile));if(user == null) {throw new GlobalException(CodeMsg.MOBILE_NOT_EXIST);}//驗證密碼String dbPass = user.getPassword();String saltDB = user.getSalt();if(!PasswordHelper.checkCredentials(formPass, saltDB, dbPass)) {throw new GlobalException(CodeMsg.PASSWORD_ERROR);}//生成cookieString token = UUIDUtil.uuid();addCookie(response, token, user);return token;}

就這樣兩次加密就完成了

JSR303和全局異常處理

全局異常處理
如果系統發生了異常,不做統一異常處理,前端會給用戶展示一大片看不懂的文字。做統一異常處理后當異常發生后可以給用戶一個溫馨的提示,不至于使用戶滿頭霧水,所以一方面是為了更好的用戶體驗 如果不統一全局異常,服務端和前端在遇到異常的時候處理起來雜亂無章非常費力。所以另一方面是為了制定規范提高工作效率

我們這里也就是通過寫一個全局異常處理類,來處理我們的運行異常,并給與相對應的提示,而不是返回500錯誤i西南西

package com.javaxl.miaosha_02.exception;import java.util.List;import javax.servlet.http.HttpServletRequest;import com.javaxl.miaosha_02.result.CodeMsg; import com.javaxl.miaosha_02.result.Result; import org.springframework.validation.BindException; import org.springframework.validation.ObjectError; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody;@ControllerAdvice @ResponseBody public class GlobalExceptionHandler {@ExceptionHandler(value=Exception.class)public Result<String> exceptionHandler(HttpServletRequest request, Exception e){e.printStackTrace();if(e instanceof GlobalException) {GlobalException ex = (GlobalException)e;return Result.error(ex.getCm());} else if(e instanceof BindException) {BindException ex = (BindException)e;List<ObjectError> errors = ex.getAllErrors();ObjectError error = errors.get(0);String msg = error.getDefaultMessage();return Result.error(CodeMsg.BIND_ERROR.fillArgs(msg));}else {return Result.error(CodeMsg.SERVER_ERROR);}} }

我們的信息提示類,也就是前面接收的封裝全局信息的類,去繼承我們的全局異常處理類,來返回錯誤提示信息

package com.javaxl.miaosha_02.exception;import com.javaxl.miaosha_02.result.CodeMsg;public class GlobalException extends RuntimeException{private static final long serialVersionUID = 1L;private CodeMsg cm;public GlobalException(CodeMsg cm) {super(cm.toString());this.cm = cm;}public CodeMsg getCm() {return cm;}}

JSR-303 是 JAVA EE 6 中的一項子規范,叫做 Bean Validation,官方參考實現是Hibernate Validator。

此實現與 Hibernate ORM 沒有任何關系。 JSR 303 用于對 Java Bean 中的字段的值進行驗證。
Spring MVC 3.x 之中也大力支持 JSR-303,可以在控制器中對表單提交的數據方便地驗證。

我們大部分前臺項目都是做了JS正則判斷的代碼,那么如果別人知道了你的請求地址,它是不是就能跳過你的js驗證,直接去訪問你的數據庫的某一個方法呢?這當然是可以的,所以我們就需要用JSR303來處理這種請求

比如我們在注冊的時候信息必須滿足格式才能插入數據庫,而果然跳過js驗證,那么數據庫就會多很多垃圾數據,這樣肯定是不行的,所以我們就加了驗證在后臺

public Result<String> doLogin(HttpServletResponse response, @Valid LoginVo loginVo) {log.info(loginVo.toString());//登錄String token = userService.login(response, loginVo);return Result.success(token);}

我在外面登錄的方法中加了自定義注解,驗證格式是否正確,只有通過了驗證才能訪問方法,否則就進入異常處理

自定義注解的代碼

package com.javaxl.miaosha_02.validator;import static java.lang.annotation.ElementType.ANNOTATION_TYPE; import static java.lang.annotation.ElementType.CONSTRUCTOR; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.RetentionPolicy.RUNTIME;import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target;import javax.validation.Constraint; import javax.validation.Payload;@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER }) @Retention(RUNTIME) @Documented @Constraint(validatedBy = {IsMobileValidator.class }) public @interface IsMobile {boolean required() default true;String message() default "手機號碼格式錯誤";Class<?>[] groups() default { };Class<? extends Payload>[] payload() default { }; }

驗證格式是否符合我們的要求

package com.javaxl.miaosha_02.validator; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext;import com.javaxl.miaosha_02.util.ValidatorUtil; import org.apache.commons.lang3.StringUtils;public class IsMobileValidator implements ConstraintValidator<IsMobile, String> {private boolean required = false;public void initialize(IsMobile constraintAnnotation) {required = constraintAnnotation.required();}public boolean isValid(String value, ConstraintValidatorContext context) {if(required) {return ValidatorUtil.isMobile(value);}else {if(StringUtils.isEmpty(value)) {return true;}else {return ValidatorUtil.isMobile(value);}}} }

所以只要加了這個注解的就都會先進入驗證才能訪問數據庫
所以我們最后直接通過錯誤格式并訪問不了,而是進了我們的錯誤處理頁面

Redis通用的key生成策略和通用的RedisService方法

通用key生成是個什么概念呢,也就相當于分組了,我們在項目中需要用到redis的地方肯定不止一個模塊,肯定很多模塊都需要用到redis,所以我們在存儲的時候生成一個文件夾,然后每一個key的名字我們以固定的格式給它拼接上,就如下圖效果

BasePrefix
我們通過放射獲取類名,然后拼接上我們的prefix

package com.javaxl.miaosha_02.redis;public abstract class BasePrefix implements KeyPrefix{private int expireSeconds;private String prefix;public BasePrefix(String prefix) {//0代表永不過期this(0, prefix);}public BasePrefix( int expireSeconds, String prefix) {this.expireSeconds = expireSeconds;this.prefix = prefix;}public int expireSeconds() {//默認0代表永不過期return expireSeconds;}public String getPrefix() {String className = getClass().getSimpleName();return className+":" + prefix;} }

MiaoshaUserKey生成策略
這也就是生成我們的prefix和規定我們的過期時間的類
最終我們生成看到了就是我們的ClassName+prefix所生成的key

package com.javaxl.miaosha_02.redis;public class MiaoshaUserKey extends BasePrefix{public static final int TOKEN_EXPIRE = 3600*24 * 2;private MiaoshaUserKey(int expireSeconds, String prefix) {super(expireSeconds, prefix);}public static MiaoshaUserKey token = new MiaoshaUserKey(TOKEN_EXPIRE, "tk");public static MiaoshaUserKey getById = new MiaoshaUserKey(0, "id"); }

通用的Redis操作類
高并發redis做緩存是很通用的手段
當數據量過大時操作redis就有可能出現重復的現象

然后我們通過泛型封裝一個通用的存值、取值、自增、自減等操縱的方法,盡量來避免這些問題

package com.javaxl.miaosha_02.redis;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;import com.alibaba.fastjson.JSON;import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool;@Service public class RedisService {@AutowiredJedisPool jedisPool;/*** 獲取當個對象* */public <T> T get(KeyPrefix prefix, String key, Class<T> clazz) {Jedis jedis = null;try {jedis = jedisPool.getResource();//生成真正的keyString realKey = prefix.getPrefix() + key;String str = jedis.get(realKey);T t = stringToBean(str, clazz);return t;}finally {returnToPool(jedis);}}/*** 設置對象* */public <T> boolean set(KeyPrefix prefix, String key, T value) {Jedis jedis = null;try {jedis = jedisPool.getResource();String str = beanToString(value);if(str == null || str.length() <= 0) {return false;}//生成真正的keyString realKey = prefix.getPrefix() + key;int seconds = prefix.expireSeconds();if(seconds <= 0) {jedis.set(realKey, str);}else {jedis.setex(realKey, seconds, str);}return true;}finally {returnToPool(jedis);}}/*** 判斷key是否存在* */public <T> boolean exists(KeyPrefix prefix, String key) {Jedis jedis = null;try {jedis = jedisPool.getResource();//生成真正的keyString realKey = prefix.getPrefix() + key;return jedis.exists(realKey);}finally {returnToPool(jedis);}}/*** 刪除* */public boolean delete(KeyPrefix prefix, String key) {Jedis jedis = null;try {jedis = jedisPool.getResource();//生成真正的keyString realKey = prefix.getPrefix() + key;long ret = jedis.del(key);return ret > 0;}finally {returnToPool(jedis);}}/*** 增加值* */public <T> Long incr(KeyPrefix prefix, String key) {Jedis jedis = null;try {jedis = jedisPool.getResource();//生成真正的keyString realKey = prefix.getPrefix() + key;return jedis.incr(realKey);}finally {returnToPool(jedis);}}/*** 減少值* */public <T> Long decr(KeyPrefix prefix, String key) {Jedis jedis = null;try {jedis = jedisPool.getResource();//生成真正的keyString realKey = prefix.getPrefix() + key;return jedis.decr(realKey);}finally {returnToPool(jedis);}}private <T> String beanToString(T value) {if(value == null) {return null;}Class<?> clazz = value.getClass();if(clazz == int.class || clazz == Integer.class) {return ""+value;}else if(clazz == String.class) {return (String)value;}else if(clazz == long.class || clazz == Long.class) {return ""+value;}else {return JSON.toJSONString(value);}}@SuppressWarnings("unchecked")private <T> T stringToBean(String str, Class<T> clazz) {if(str == null || str.length() <= 0 || clazz == null) {return null;}if(clazz == int.class || clazz == Integer.class) {return (T)Integer.valueOf(str);}else if(clazz == String.class) {return (T)str;}else if(clazz == long.class || clazz == Long.class) {return (T)Long.valueOf(str);}else {return JSON.toJavaObject(JSON.parseObject(str), clazz);}}private void returnToPool(Jedis jedis) {if(jedis != null) {jedis.close();}}}

程序猿的必讀書籍

第一階段:

《C語言程序與設計》
《c++進階寶典》
《Java數據結構和算法》

第二階段:

《教你怎么不生氣》
《老子》
《沉默的憤怒》

第三階段:

《頸椎病康復指南》
《腰椎間盤突出日常護理》
《強迫癥的自我恢復》

第四階段:

《活著》

end…

總結

以上是生活随笔為你收集整理的java优化代码常见套路的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。