1 基本类型使用优化
1.1 尽量重用对象
特别是对于String对象的使用,如需拼接字符串,使用如下例子:
//拼接字符串,不重视效率的写法 String str1 = "aaa"; str1 = str1 + "bbb"; //拼接字符串,效率高的写法 StringBuilder sb = new StringBuilder(str1); sb.append("bbb");
1.2 尽量减少对变量的重复计算
//造成重复计算的例子 for(int i = 0; i < list.size(); i++){ ... } //避免重复计算的例子 int length = list.size(); for(int i = 0; i < length; i++){ ... }
1.3 尽量采用懒加载策略,即在需要时候才创建
//错误的例子 String str = "aaa"; if (i == 1){ list.add(str); } //正确的例子 if(i == 1){ String str = "aaa"; list.add(str); }
1.4 乘法和除法使用位移操作
//常用 for(int i = 0; i < 100; i++){ a = i * 8; b = i / 2; } //使用位移操作 for(int i = 0; i < 100; i++){ a = i << 3; b = i >> 1; }
1.5 把一个数字类型转为字符串
Integer id = 10; String str = id.toString(); --最快 String str = String.valueOf(id); --最快 String str = id + “”; -- 最慢
1.6 使用最有效率的方式去遍历Map
Map<Integer,String> map = new HashMap<Integer,String>(); map.put(1,"A"); Set<Map.Entry<Integer,String>> entrySet = map.entrySet(); Iterator<Map.Entry<Integer,String>> iter = entrySet.iterator();
while(iter.hasNext()){ Map.Entry<Integer,String> entry = iter.Next(); System.out.println(entry.getKey() + " -- " + entry.getValue()); }
2 类使用优化
2.1 尽量指定类、方法的final修饰符
2.2 及时关闭流(IO)
2.3 慎用异常: 异常对性能不利。抛出异常首先要创建一个新对象, 只要有异常被抛出,JVM就必须调整调用堆栈,因为在处理过程中创建了一个新的对象。异常只能用于错误处理,不应该用来控制程序流程。
2.4 不要在循环中使用try ... catch ...
除非不得已的情况下,否则在循环中使用try ... catch ... 会照成出现异常后依然继续执行循环的情况出现!
2.5 循环内不要不断创建对象引用
//错误的写法 for(int b = 0; b < count; b++){ Object o = new Object(); } //正确的写法 Object o = null; for(int b = 0; b < count; b++){ o = new Object(); }
2.6 尽量使用HashMap、ArrayList、StringBuilder。除非线程需要,否则不推荐使用HashTable、Vector、StringBuffer,后三者由于使用了同步机制而导致性能开销。
2.7 尽量在合适的场合使用单例
使用单例可以减轻加载的负担、缩短加载的时间,提高加载的效率,但并不是所有地方都适合单例,单例主要适合以下3个方面:
1)控制资源的使用,通过线程同步来控制资源的并发访问
2)控制实例的产生,以达到节约资源的目的
3)控制数据的共享,在不建立直接关联的条件下,让多个不相干的进程或线程之间实现通信
2.8 尽量避免随意使用静态变量
当某个对象被定义为static的时候,会存储在方法区中,GC对于回收方法区内的对象是需要非常严苛的条件的。这会导致该静态对象常驻于内存,直到程序终止。
2.8 及时清除不再需要的会话
当内存不足的时候,系统会把部分会话数据转移到磁盘,那么就必须先对数据进行序列化,在大规模集群中,对对象进行序列化的代价是很昂贵的。因此,在会话不再需要时,因及时的调用HttpSession.invalidate()方法清除会话。
2.9 使用同步代码块替代同步方法
synchronized
关键字给我们的代码加锁。 通常有两种写法:在方法上加锁
和 在代码块上加锁。
除非能确定一整个方法都是需要同步的,否则尽量使用同步代码块,避免对那些不需要进行同步的代码也进行了同步,影响了代码执行效率。
在方法上加锁:
public synchronized doSave(String fileUrl) { mkdir(); uploadFile(fileUrl); sendMessage(fileUrl); }
这里加锁的目的是为了防止并发的情况下,创建了相同的目录,第二次会创建失败,影响业务功能。
在代码块上加锁:
public void doSave(String path,String fileUrl) { synchronized(this) { if(!exists(path)) { mkdir(path); } } uploadFile(fileUrl); sendMessage(fileUrl); }
2.10 使用数据库连接池和线程池
这两个池都能很好的用于对象的重用,前者可以避免频繁的打开和关闭连接,后者可以避免频繁的创建和销毁线程。
2.11 字符串变量和字符串常量equals的时候将字符串常量写在前面,这么 做主要是避免出现空指针异常。
2.12 减少for循环次数
如果循环层级比较深,循环中套循环,可能会影响代码的执行效率。
如果有两层循环,如果userList和roleList数据比较多的话,需要循环遍历很多次,才能获取我们所需要的数据,非常消耗cpu资源
低效率:
//正常逻辑2层for循环处理 for(User user: userList) { for(Role role: roleList) { if(user.getRoleId().equals(role.getId())) { user.setRoleName(role.getName()); } } }
优化:
Map<Long, List<Role>> roleMap = roleList.stream().collect(Collectors.groupingBy(Role::getId)); for (User user : userList) { List<Role> roles = roleMap.get(user.getRoleId()); if(CollectionUtils.isNotEmpty(roles)) { user.setRoleName(roles.get(0).getName()); } }
优化思想就是减少循环次数,最简单的办法是,把第二层循环的集合变成map
,这样可以直接通过key
,获取想要的value
数据。
虽说map的key存在hash冲突
的情况,但遍历存放数据的链表
或者红黑树
的时间复杂度
,比遍历整个list集合要小很多。
2.13 消除if...else的锦囊妙计,反射时添加缓存
优化前:
publicinterface IPay { void pay(); } @Service publicclass AliaPay implements IPay { @Override public void pay() { System.out.println("===发起支付宝支付==="); } } @Service publicclass WeixinPay implements IPay { @Override public void pay() { System.out.println("===发起微信支付==="); } } @Service publicclass JingDongPay implements IPay { @Override public void pay() { System.out.println("===发起京东支付==="); } } @Service publicclass PayService { @Autowired private AliaPay aliaPay; @Autowired private WeixinPay weixinPay; @Autowired private JingDongPay jingDongPay; public void toPay(String code) { if ("alia".equals(code)) { aliaPay.pay(); } elseif ("weixin".equals(code)) { weixinPay.pay(); } elseif ("jingdong".equals(code)) { jingDongPay.pay(); } else { System.out.println("找不到支付方式"); } } }View Code
优化后:
/** * @Author: Ywh * @Date: 2022/7/25 14:50 * @Description */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface PayCode { String value(); String name(); } @PayCode(value = "alia", name = "支付宝支付") @Component("alia") public class AliaPay implements IPay { @Override public void pay() { System.out.println("===发起支付宝支付==="); } } @PayCode(value = "jingdong", name = "京东支付") @Component("jingdong") public class JingDongPay implements IPay { @Override public void pay() { System.out.println("===发起京东支付==="); } } @PayCode(value = "weixin", name = "微信支付") @Component("weixin") public class WeixinPay implements IPay { @Override public void pay() { System.out.println("===发起微信支付==="); } } @Service @Slf4j public class PayService2 implements ApplicationListener<ContextRefreshedEvent> { private static Map<String, IPay> payMap = null; @Override public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { //在初始化或刷新ApplicationContext时发布 ApplicationContext applicationContext = contextRefreshedEvent.getApplicationContext(); //获取所有拥有特定payCode注解的Bean(AliPay、WeiXinPay、JindDongPay) Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(PayCode.class); if (beansWithAnnotation != null) { payMap = new HashMap<>(); beansWithAnnotation.forEach((key, value) -> { String bizType = value.getClass().getAnnotation(PayCode.class).value(); payMap.put(bizType, (IPay) value); }); } } public void pay(String code) { payMap.get(code).pay(); } } @GetMapping("/pay") @ApiOperation("测试支付") public void pay(String code){ payService2.pay(code); }View Code
2.14 不要满屏try...catch异常
可以使用全局异常处理:RestControllerAdvice
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public String handleException(Exception e) { if (e instanceof ArithmeticException) { return "数据异常"; } if (e instanceof Exception) { return "服务器内部异常"; } retur nnull; } }
2.15 状态用枚举
public enum OrderStatusEnum { CREATE(1, "下单"), PAY(2, "支付"), DONE(3, "完成"), CANCEL(4, "撤销"); private int code; private String message; OrderStatusEnum(int code, String message) { this.code = code; this.message = message; } public int getCode() { return this.code; } public String getMessage() { return this.message; } public static OrderStatusEnum getOrderStatusEnum(int code) { return Arrays.stream(OrderStatusEnum.values()).filter(x -> x.code == code).findFirst().orElse(null); } }View Code
-
代码的可读性变强了,不同的状态,有不同的枚举进行统一管理和维护。
-
枚举是天然单例的,可以直接使用==号进行比较。
-
code和message可以成对出现,比较容易相关转换。
-
枚举可以消除if...else过多问题。
2.16 少用@Transactional注解,避免大事务
可以使用编程式事务
,在spring
项目中使用TransactionTemplate
类的对象,手动执行事务。
@Autowired private TransactionTemplate transactionTemplate; ... public void save(final User user) { transactionTemplate.execute((status) => { doSameThing... return Boolean.TRUE; }) }
2.17 SimpleDateFormat线程不安全,使用java8的DateTimeFormatter类。
2.18 少用Executors创建线程池
优先推荐使用ThreadPoolExecutor
类,我们自定义线程池。
ExecutorService threadPool = new ThreadPoolExecutor( 8, //corePoolSize线程池中核心线程数 10, //maximumPoolSize 线程池中最大线程数 60, //线程池中线程的最大空闲时间,超过这个时间空闲线程将被回收 TimeUnit.SECONDS,//时间单位 new ArrayBlockingQueue(500), //队列 new ThreadPoolExecutor.CallerRunsPolicy()); //拒绝策略
标签:code,JAVA,String,pay,void,代码优化,线程,public From: https://www.cnblogs.com/ningshare/p/16909824.html