关于创建、销毁对象⭐Java程序员需要掌握的8个编程好习惯

简介: 关于创建、销毁对象⭐Java程序员需要掌握的8个编程好习惯

关于创建、销毁对象⭐Java程序员需要掌握的8个编程好习惯

本文基于Effective Java中创建和销毁对象的章节汇总出8个相关的好习惯(文末附案例地址)

思维导图如下:

image.png

1.静态工厂代替构造器

1.可以自定义名称,见名知意

见名知意的方法更容易理解,比如 getInstanceByCode 根据Code获取实例

2.获取对象时,可以使用单例、享元等思想进行复用

Boolean value = Boolean.valueOf(true);
public static Boolean valueOf(boolean b) {
    return (b ? TRUE : FALSE);
}

3.可以返回原类型的子类

Collections.singletonList(null);
public static <T> List<T> singletonList(T o) {
    return new SingletonList<>(o);
}

4.返回对象可以随着入参发生改变

根据入参key的不同可以获取不同的策略

public static <T extends XXStrategy> T getStrategyByKey(String key) {
    return (T) strategyFactory.get(key);
}

5.返回对象的类可以在编写静态工厂时不存在

在编写静态工厂中获取对象时,对象可以不存在(未编译),通过反射的手段在运行时加载进来

典型的例子就是JDBC,在使用前通过反射加载驱动

Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection("url", "username", "password");

小结

业务中使用场景挺多的,比如:spring的getBean、实现业务的策略工厂(基本上能覆盖1-5特点)

策略工厂可以使用Map维护code以及对应的策略,这样就已经实现1、2、4

实现3时还需要使用泛型进行转换(上面案例给出),使用反射实现5

2.多个构造器参数考虑建造者模式

构造器的入参太多时容易弄混,还好现在的IDE开发工具可以提示参数名称,如果参数名称取的一团糟也会容易混淆

在这种场景下可以选择建造者模式 Builder

        //构造器
        Student student = new Student("张三", 18, "男", "北京", "13812345678", "", "12345678");
        
        //Builder
        Student.builder()
                .name("菜菜的后端私房菜")
                .age(18)
                .sex("男")
                .address("北京")
                .phone("13812345678")
                .email("")
                .qq("12345678")
                .build();

提高阅读性、多建一个类的开销、可以防止对象在构造期间逃逸

3.私有构造或枚举强化单例

私有构造防止调用构造创建

可以通过字段直接获取单例,也可以通过静态工厂方法获取单例 (饿汉式)

//通过字段
SingletonField singletonField = SingletonField.INSTANCE;
//通过静态工厂方法
SingletonStaticFactory singletonStaticFactory = SingletonStaticFactory.getInstance();
//通过枚举
SingletonEnum singletonEnum = SingletonEnum.INSTANCE;

通过反射、JDK序列化依旧可以调用构造,破坏单例

使用枚举避免反射调用单例

反射在实例化前会判断是否枚举,枚举则抛出异常

if ((clazz.getModifiers() & Modifier.ENUM) != 0)
    throw new IllegalArgumentException("Cannot reflectively create enum objects");

4.考虑依赖注入

构造器注入,能够灵活使用多种依赖

    static class DependencyInjectionNotUse {
        private Util util = new Util();
        public DependencyInjectionNotUse() {
        }
    }
    static class DependencyInjectionUse {
        private Util util;
        public DependencyInjectionUse(Util util) {
            this.util = util;
        }
    }

依赖太多在大项目中会很乱,可以使用DI框架如 spring的IOC

5.避免创建不必要的对象

//创建了不必要对象
String a = new String("菜菜的后端私房菜");
String b = "菜菜的后端私房菜";

自动拆装箱,也会创建不必要对象(先转成long相加,再转Long)

        Long sum = 0L;
        for (long i = 0; i <= Integer.MAX_VALUE; i++) {
            sum += i;
//            Long.valueOf(sum = sum.longValue() + i);
        }

多使用单例、享元模式,复用资源,避免创建不必要对象:字符串、自动拆装箱等

6.消除过期的对象引用

Java采用引用计数法,如果不再使用对象时需要置空,否则会认为还要使用,从而导致内存泄漏

    public Object pop() {
        if (size == 0)
            throw new EmptyStackException();
        //出栈时需要将元素清除,不再引用
        //elements[size-1] = null
        return elements[--size];
    }

缓存、监听器也可能导致内存泄漏,注意使用弱引用或注意关闭

7.不使用finalize方法

finalize 由守护线程执行,无法预估执行的时机

finalize 为不可达对象才会执行的方法,如果要清楚资源使用finally关闭资源

感兴趣的同学可以查看这篇文章:如何判断对象“已死”

8.try-with-resources优于try-finally

twr会自动关闭资源,优先使用

        //try-finally
        BufferedReader br = new BufferedReader(new FileReader(path));
        try {
            return br.readLine();
        } finally {
            br.close();
        }
        //twr try-with-resources
        try (BufferedReader br = new BufferedReader(new FileReader(path))) {
            return br.readLine();
        }

总结

考虑使用静态工厂方法代替构造器,静态工厂方法能够见名知意、可以使用单例或享元模式返回对象、搭配泛型返回对象可以是原类型子类、返回的对象可以随着入参改变、返回的对象所在的类可以在编译期不存在

在参数较多时可以考虑使用建造者模式,可以代码可读性更高、防止构造对象期间发生逃逸

可以通过私有构造强化单例,但能够被反射、序列号破坏单例;使用枚举单元素强化单例则可以避免破坏(在反射实例化前判断为枚举则抛出异常)

对象依赖的“工具”不是固定的时,可以采用依赖注入DI的方式进行改变,而不是直接写死;频繁使用DI在大项目中会比较混乱,使用DI框架可以解决,比如 Spring 的IOC

避免创建不必要的对象,如String的字符串常量、基本类型与包装类型的自动拆装箱

消除过期的引用对象:不再使用对象时,需要消除引用关系,否则基于引用计数法的Java则无法给对象进行回收,从而导致内存泄漏

不使用finalize方法:finalize方法是只有对象成为不可达对象才会调用,而且由守护线程执行,无法预估执行时机,不要使用其做清理工作

try-with-resources优于try-finally:twr自动关闭资源,避免忘记,在多层嵌套时阅读性也较好

最后(不要白嫖,一键三连求求拉~)

本篇文章被收入专栏 Effective Java,感兴趣的同学可以持续关注喔

本篇文章笔记以及案例被收入 Gitee-CaiCaiJavaGithub-CaiCaiJava 感兴趣的同学可以stat下持续关注喔~

有什么问题可以在评论区交流,如果觉得菜菜写的不错,可以点赞、关注、收藏支持一下~

关注菜菜,分享更多干货,公众号:菜菜的后端私房菜

目录
打赏
0
5
5
0
63
分享
相关文章
Java程序员在AI时代必会的技术:Spring AI
在AI时代,Java程序员需掌握Spring AI技术以提升竞争力。Spring AI是Spring框架在AI领域的延伸,支持自然语言处理、机器学习集成与自动化决策等场景。它简化开发流程,无缝集成Spring生态,并提供对多种AI服务(如OpenAI、阿里云通义千问)的支持。本文介绍Spring AI核心概念、应用场景及开发步骤,含代码示例,助你快速入门并构建智能化应用,把握AI时代的机遇。
k8s的出现解决了java并发编程胡问题了
Kubernetes通过提供自动化管理、资源管理、服务发现和负载均衡、持续交付等功能,有效地解决了Java并发编程中的许多复杂问题。它不仅简化了线程管理和资源共享,还提供了强大的负载均衡和故障恢复机制,确保应用程序在高并发环境下的高效运行和稳定性。通过合理配置和使用Kubernetes,开发者可以显著提高Java应用程序的性能和可靠性。
66 31
注解的艺术:Java编程的高级定制
注解是Java编程中的高级特性,通过内置注解、自定义注解及注解处理器,可以实现代码的高度定制和扩展。通过理解和掌握注解的使用方法,开发者可以提高代码的可读性、可维护性和开发效率。在实际应用中,注解广泛用于框架开发、代码生成和配置管理等方面,展示了其强大的功能和灵活性。
66 25
【AI程序员】通义灵码 AI 程序员全面上线JAVA使用体验
通过 AI 程序编写一个JAVA后台项目登陆页面
466 42
重学Java基础篇—Java对象创建的7种核心方式详解
本文全面解析了Java中对象的创建方式,涵盖基础到高级技术。包括`new关键字`直接实例化、反射机制动态创建、克隆与反序列化复用对象,以及工厂方法和建造者模式等设计模式的应用。同时探讨了Spring IOC容器等框架级创建方式,并对比各类方法的适用场景与优缺点。此外,还深入分析了动态代理、Unsafe类等扩展知识及注意事项。最后总结最佳实践,建议根据业务需求选择合适方式,在灵活性与性能间取得平衡。
59 3
在线编程实现!如何在Java后端通过DockerClient操作Docker生成python环境
以上内容是一个简单的实现在Java后端中通过DockerClient操作Docker生成python环境并执行代码,最后销毁的案例全过程,也是实现一个简单的在线编程后端API的完整流程,你可以在此基础上添加额外的辅助功能,比如上传文件、编辑文件、查阅文件、自定义安装等功能。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
在线编程实现!如何在Java后端通过DockerClient操作Docker生成python环境
Java对象创建和访问
Java对象创建过程包括类加载检查、内存分配(指针碰撞或空闲列表)、内存初始化、对象头设置及初始化方法执行。访问方式有句柄和直接指针两种,前者稳定但需额外定位,后者速度快。对象创建涉及并发安全、垃圾回收等机制。
Java对象创建和访问
Java中判断一个对象是否是空内容
在 Java 中,不同类型的对象其“空内容”的定义和判断方式各异。对于基本数据类型的包装类,空指对象引用为 null;字符串的空包括 null、长度为 0 或仅含空白字符,可通过 length() 和 trim() 判断;集合类通过 isEmpty() 方法检查是否无元素;数组的空则指引用为 null 或长度为 0。
课时6:Java编程起步
课时6:Java编程起步,主讲人李兴华。课程摘要:介绍Java编程的第一个程序“Hello World”,讲解如何使用记事本或EditPlus编写、保存和编译Java源代码(*.java文件),并解释类定义、主方法(public static void main)及屏幕打印(System.out.println)。强调类名与文件名一致的重要性,以及Java程序的编译和执行过程。通过实例演示,帮助初学者掌握Java编程的基本步骤和常见问题。
|
3月前
|
Object取值转java对象
通过本文的介绍,我们了解了几种将 `Object`类型转换为Java对象的方法,包括强制类型转换、使用 `instanceof`检查类型和泛型方法等。此外,还探讨了在集合、反射和序列化等常见场景中的应用。掌握这些方法和技巧,有助于编写更健壮和类型安全的Java代码。
142 17
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等