常用的java开发技巧总结

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 常用的java开发技巧总结

常用的规范技巧总结


1.类的命名使用驼峰式命名的规范,例如:UserService,但是以下情景例外:DO / BO / PO / DTO / VO。例如说:


UserPO,StudentPO(PO,VO,DTO,等这类名词需要全大写)


@Data
@Builder
public class CustomBodyDTO {
    private String name;
    private String idCode;
    private String status;
}
复制代码


2.如果在模块或者接口,类,方法中使用了设计模式,那么请在命名的时候体现出来,例如说:


TokenFactory,LoginProxy等。


public class TokenFactory {
    public TokenDTO buildToken(LoginInfo loginInfo) {
        String token = UUID.randomUUID().toString();
        TokenDTO tokenDTO = TokenDTO.builder()
                .token(token)
                .createTime(LocalDateTime.now())
                .build();
        String redisKey = RedisKeyBuilder.buildTokenKey(token);
        redisService.setObject(redisKey, loginInfo, Timeout.ONE_DAY * 30 * 2);
        log.info("创建token成功|loginInfo={}", loginInfo.toString());
        return tokenDTO;
    }
}
复制代码


3.Object 的 equals 方法容易抛空指针异常。


从源码来进行分析equals方法是属于Object类的,如果调用方为null,那么自然在运行的时候会抛出空指针异常的情况。


object类中的源码:


public boolean equals(Object obj) {
        return (this == obj);
    }
复制代码


为了避免这种现况出现,在比对的时候尽量将常量或者有确定值的对象置前。:


例如说:


正确:“test”.equals(object);
错误:object.equals(“test”);
复制代码


4.对于所有相同类型的包装类进行比较的时候,都是用equal来进行操作。对于Integer类来说,当相应的变量数值范围在-128到127之间的时候,该对象会被存储在IntegerCache.cache里面,因此会有对象复用的情况发生,所以对于包装类进行比较的时候,最好统一使用equal方法。


private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];
        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;
            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);
            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }
        private IntegerCache() {}
    }
  public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
复制代码


5.所有的pojo类中的属性最好统一使用包装类属性类型数据。RPC方法的返回值和参数都统一使用包装类数据。局部变量中使用基本的数据类型。


对于实际的应用场景来说,例如说一个学生类,当我们设置里面的成绩字段为int类型的时候,如果学生没有考试,那么这个成绩字段应该为空,但是int默认会赋值为0,那么这个时候使用基本数据类型就容易产生误区,到底是考了0分,还是说没有参加考试。如果换成使用包装类Integer类型的话,就可以通过null值来进行区分了。


6.当pojo类在进行编写的时候要重写相应的toString方法,如果该pojo中继承了另外的一个pojo类,那么请在相应的tostring函数中加入super.toString()方法。通过重写toString方法有利于在日志输出的时候查看相应对象的属性内容进行逐一分析,对于一些有继承关系的对象而言,加入了super.toString方法更加有助于对该对象的理解和分析。


7.在pojo的getter和setter方法里面,不要增加业务逻辑的代码编写,这样会增加问题排查的难度。


正确做法:
public class User {
    private Integer id;
    private String username;
    public Integer getId() {
        return id;
    }
    public User setId(Integer id) {
        this.id = id;
        return this;
    }
    public String getUsername() {
        return username;
    }
    public User setUsername(String username) {
        this.username = username;
        return this;
    }
}
错误做法:
public class User {
    private Integer id;
    private String username;
    public Integer getId() {
        return id;
    }
    public User setId(Integer id) {
        this.id = id;
        return this;
    }
    public String getUsername() {
        return "key-prefix-"+username;
    }
    public User setUsername(String username) {
        this.username = "key-prefix-"+username;
        return this;
    }
}
复制代码


8.final 可以声明类、成员变量、方法、以及本地变量,下列情况使用 final 关键字:


1) 不允许被继承的类,如:String 类。


2) 不允许修改引用的域对象,如:POJO 类的域变量。


3) 不允许被重写的方法,如:POJO 类的 setter 方法。


4) 不允许运行过程中重新赋值的局部变量。


5) 避免上下文重复使用一个变量,使用 final 描述可以强制重新定义一个变量,方便更好

地进行重构。


9.对于任何类而言,只要重写了equals就必须重写hashcode。


举例说明:


1)HashSet在存储数据的时候是存储不重复对象的,这些对象在进行判断的时候需要依赖hashcode和equals方法,因此需要重写。


2)在自定义对象作为key键时,需要重写hashcode和equals方法,例如说String类就比较适合用于做key来使用。


10.不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator方式,如果并发操作,需要对 Iterator 对象加锁。


Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if (删除元素的条件) {
iterator.remove();
}
}
复制代码


11.使用HashMap的时候,可以指定集合的初始化大小。


例如说,HashMap里面需要存放10000个元素,但是由于没有进行初始化大小操作,所以在添加元素的时候,hashmap的内部会一直在进行扩容操作,影响性能。那么为了减少扩容操作,可以在初始化的时候将hashmap的大小设置为:已知需要存储的大小/负载因子(0.75)+1


HashMap hashMap=new HashMap<>(13334);
复制代码


12.Map类集合中,K/V对于null类型存储的情况:


集合名称 key value 说明
HashMap 允许为null 允许为null 线程不安全
TreeMap 不允许为null 允许为null 线程不安全
HashTable 不允许为null 不允许为null 线程安全
ConcurrentHashMap 不允许为null 不允许为null 线程安全


13.可以利用 Set 元素唯一的特性,可以快速对一个集合进行去重操作,避免使用 List 的

contains 方法进行遍历、对比、去重操作。


通关观察可以发现,HashSet底层通过将传入的值再传入到一个HashMap里面去进行操作,进入到HashMap里面之后,会先通过调用该对象的hashcode来判断是否有重复的值,如果有再进行equals判断,如果没有相同元素则插入处理。


public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
复制代码


14.线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样

的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。

错误做法:


ExecutorService executors = Executors.newSingleThreadExecutor();
      ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
复制代码


对于线程池的参数需要有深入的理解后,结合实际的机器参数来进行参数设置,从而防止在使用中出现异常。


ExecutorService fixedExecutorService = new ThreadPoolExecutor(
                1,
                2, 
                60,
                TimeUnit.SECONDS,
                 linkedBlockingQueue, 
                new MyThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()
        );
复制代码


ps:使用Executors.new方式创建线程池的缺点: *


对于FixedThreadPool 和 SingleThreadPool而言


允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。


对于CachedThreadPool 和 ScheduledThreadPool而言


允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。


15.使用一些日期类的时候,推荐使用LocalDateTime来替代Calendar类,或者说使用Instant来替代掉Date类。


16.尽量避免在for循环里面执行try-catch操作,可以选择将try-catch操作放在循环体外部使用。


正确做法:
        try {
            for (int i = 0; i < 100; i++) {
                doSomeThing();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
不推荐做法:
       for (int i = 0; i < 100; i++) {
            try {
                doSomeThing();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
复制代码


17.对于大段的代码进行try-catch操作,这是一种不负责任的行为,将稳定的代码也都包围在了try-catch语句块里面没能很好的分清代码的稳定性范围。通常我们称在运行中不会出错的代码块为稳定性代码,可能会有异常出错的部分为非稳定性代码块,后者才是try-catch重点需要关注的对象。


18.在jdk7之后,对于流这类需要关闭连接释放资源的对象,可以使用try-with-resource处理机制来应对。例如下方代码:


File file = new File("*****");
        try (FileInputStream fin = new FileInputStream(file)) {
            //执行相关操作
        } catch (Exception e) {
            //异常捕获操作
        }
复制代码


19.使用ArrayList的时候,如果清楚它的指定大小的话,可以尽量在初始化的时候进行大小指定,因为随着arraylist不断添加新的元素之后,链表的体积会不断增大扩容。


private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
复制代码


20.对于一些短信,邮件,电话,下单,支付等应用场景而言,开发的时候需要设置相关的防重复功能限制,防止出现某些恶意刷单,滥刷这类型情况。


21.对于敏感词汇发表的时候,需要考虑一些文本过滤的策略,这一块的功能可以考虑直接接入市面上已有的成熟的UGC监控服务,或者使用公司内部自研的ugc过滤工具,防止用户发表恶意评论等情况出现。


22.在建立索引的时候,对于索引的命名需要遵循一定的规范:


索引类型 命名规则 案例
主键索引 pk_字段名,pk是指primary key pk_order_id
唯一索引 uk_字段名,uk是指 unique key uk_order_id
普通索引 idx_字段名,idx是指 index idx_order_id


23.当我们需要存储一段文本信息的时候,需要先考虑存储文本的长度,如果文本的长度超过了5000,则不建议再选择使用varchar类型来进行存储,可以考虑使用text类型进行数据存储,这个时候可以考虑单独用一张表来进行存储数据,并且通过一个额外的主键id来对应,从而避免影响其他字段的查询。


24.在进行数据库命名的时候尽量保证数据库的名称和项目工程的名称一致。


25.在进行表结构设计的时候,只要具有唯一性质的字段都需要建立唯一索引,这样有助于后期进行查询的时候提高查询的效率,没有唯一索引这一层的保障,即使在业务层加入了拦截,但是依然容易造成线上脏数据的产生。


26.在进行order by这类型sql查询的时候,需要注意查询索引的有序性,关于索引的建立,可以去了解一下索引的星级评定,例如三星索引。但是个人认为索引没有所谓的最优性,需要结合实际的业务场景来设计。


21.在MySQL中,使用count(*)会统计值为 NULL 的行,而 count(列名)不会统计此列为 NULL 值的行.


22.在进行数据库存储引擎选择的时候,需要结合相关的应用场景来选择,如果是需要应用在select操作较多的情况下,可以选择使用MyIsAM存储引擎,如果是对于数据的insert,update,这类修改操作较多的业务场景,则优先推荐使用innodb存储引擎。目前普遍互联网公司都推荐使用innodb较多。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
1月前
|
Java
Java开发实现图片URL地址检验,如何编码?
【10月更文挑战第14天】Java开发实现图片URL地址检验,如何编码?
68 4
|
9天前
|
Java API Maven
如何使用Java开发抖音API接口?
在数字化时代,社交媒体平台如抖音成为生活的重要部分。本文详细介绍了如何用Java开发抖音API接口,从创建开发者账号、申请API权限、准备开发环境,到编写代码、测试运行及注意事项,全面覆盖了整个开发流程。
52 10
|
1月前
|
监控 Java 测试技术
Java开发现在比较缺少什么工具?
【10月更文挑战第15天】Java开发现在比较缺少什么工具?
36 1
|
1月前
|
Java
Java开发实现图片地址检验,如果无法找到资源则使用默认图片,如何编码?
【10月更文挑战第14天】Java开发实现图片地址检验,如果无法找到资源则使用默认图片,如何编码?
59 2
|
15天前
|
SQL 安全 Java
安全问题已经成为软件开发中不可忽视的重要议题。对于使用Java语言开发的应用程序来说,安全性更是至关重要
在当今网络环境下,Java应用的安全性至关重要。本文深入探讨了Java安全编程的最佳实践,包括代码审查、输入验证、输出编码、访问控制和加密技术等,帮助开发者构建安全可靠的应用。通过掌握相关技术和工具,开发者可以有效防范安全威胁,确保应用的安全性。
34 4
|
17天前
|
缓存 监控 Java
如何运用JAVA开发API接口?
本文详细介绍了如何使用Java开发API接口,涵盖创建、实现、测试和部署接口的关键步骤。同时,讨论了接口的安全性设计和设计原则,帮助开发者构建高效、安全、易于维护的API接口。
44 4
|
27天前
|
开发框架 JavaScript 前端开发
HarmonyOS UI开发:掌握ArkUI(包括Java UI和JS UI)进行界面开发
【10月更文挑战第22天】随着科技发展,操作系统呈现多元化趋势。华为推出的HarmonyOS以其全场景、多设备特性备受关注。本文介绍HarmonyOS的UI开发框架ArkUI,探讨Java UI和JS UI两种开发方式。Java UI适合复杂界面开发,性能较高;JS UI适合快速开发简单界面,跨平台性好。掌握ArkUI可高效打造符合用户需求的界面。
86 8
|
22天前
|
SQL Java 程序员
倍增 Java 程序员的开发效率
应用计算困境:Java 作为主流开发语言,在数据处理方面存在复杂度高的问题,而 SQL 虽然简洁但受限于数据库架构。SPL(Structured Process Language)是一种纯 Java 开发的数据处理语言,结合了 Java 的架构灵活性和 SQL 的简洁性。SPL 提供简洁的语法、完善的计算能力、高效的 IDE、大数据支持、与 Java 应用无缝集成以及开放性和热切换特性,能够大幅提升开发效率和性能。
|
23天前
|
存储 Java 关系型数据库
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践,包括连接创建、分配、复用和释放等操作,并通过电商应用实例展示了如何选择合适的连接池库(如HikariCP)和配置参数,实现高效、稳定的数据库连接管理。
43 2
|
23天前
|
监控 Java 数据库连接
在Java开发中,数据库连接管理是关键问题之一
在Java开发中,数据库连接管理是关键问题之一。本文介绍了连接池技术如何通过预创建和管理数据库连接,提高数据库操作的性能和稳定性,减少资源消耗,并简化连接管理。通过示例代码展示了HikariCP连接池的实际应用。
19 1
下一篇
无影云桌面