Java基础

2021/11/01

jdk1.8、数据类型、面向对象、注解、常用类库

参考资料

1.1 jdk1.8特性

  • 接口:提供默认方法和静态方法
  • Lambda 表达式:把函数作为一个方法的参数
  • 函数式接口
  • 方法引用 类名::方法名
  • Stream
    • 中间操作:sorted、filter、map、flatMap、limit、peel、distinct、substream
    • 终止操作:collect、forEach、toArray、reduce、min、max、count、anyMatch、allMatch、noneMatch、findFirst、findAny
    • Collectors: Collectors.toList()、Collectors.groupingBy
  • Optional
    • 容器对象,保存类型T的值,或仅保存null
    • ofNullable
    • orElse
    • map
  • Date/Time API:LocalDate/LocalTime
  • 重复注解
  • 扩展注解的支持
  • Base64
  • JavaFX
  • 其它

1.2 数据类型

JVM启动时会创建9个对象池,用来存储8个基本数据类型的包装类对象和String对象

1.2.1.基本数据类型

boolean:布尔只能用true、false表示真假

Byte 数据范围表示

浮点类型

char(2字节)
int、float(4字节 byte=4*8位bite)
Long、double(8字节 =64bite)
float f=(float)3.4 或float f = 3.4f 在java里面,没小数点的默认是int,有小数点的默认是 double;

1B=1字节(byte)=8位(bit);
1KB=1024B=1024*8bit

1.2.基本数据类型及包装类
int(基本数据类型,栈内存)->Interger(类对象,堆内存) 等…….

1.3.自动拆箱和装箱(编译阶段)
自动装箱就是Java自动将原始类型值转换成对应的对象,比如将int的变量转换成Integer对 象,这个过程叫做装箱,反之将Integer对象转换成int类型值,这个过程叫做拆箱

1.2.2.String(final修饰的类)、StringBuilder 、 StringBuffer

  • 运行速度,在这方面运行速度快慢为:StringBuilder > StringBuffer > String
  • 在线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的
    • StringBuffer中很多方法可以带有synchronized(同步)关键字,所以可以保证线程是安全的
    • StringBuilder对象内容可以修改,不生成新的对象,在内存使用上要优于String类,在实际使用时,如果经常需要对一个字符串进行修改,例如插入、删除等操作,使用StringBuilder要更加适合一些。
    • String对象一旦产生后不可以被修改,重新赋值是两个对象了。

示例:

  • 1).String str1 = “abc” //创建对象,返回引用
    • String str2 = “abc” //String对象池中搜索到abc,不再创建,直接返回引用
    • String str3 = new String (”abc” ) //直接创建新对象,并返回引用
  • 2).StringBuffer和StringBuilder: 大量拼接字符串时用,提高效率,并且StringBuffer线程安全
  • 3).StringBuilder和String是一个变量和常量的关系。 StringBuilder效率高

1.2.3.Date

1.2.4.数组:长度固定

  • int[][] intArr = new int[5][10];
  • int intArray[ ][ ] = { {1,2}, {2,3}, {4,5} };
  • String[] cArray = new String[]{“a”,”b”,”c”,”d”,”e”}; 
  • new a[5],创建一个数组示例,长度为5,并未创建5个对象

1.2.5.枚举

  • 1.所有枚举类都是继承java.lang.Enum类,枚举enum是同class,interface同一级别的特性,
  • 2.它们都可以定义一些属性和方法,不过,因为java是单继承,所以枚举不能再继承其它类,但枚举可以实现接口。
  • 3.枚举的定义
    • 1).枚举常量没有任何修饰符
    • 2).每个常量以“,”分隔,以“;”结束枚举常量的描述。
    • 3).枚举常量必须定义在所有方法或者构造器之前。

1.2.6.类、对象

“==”和equal()区别

Hashcode()和equals()

  • hashCode()方法和equal()方法的作用一样,都用来对比两个对象是否相等
  • equal()相等的两个对象hashCode()肯定相等,用equal()绝对可靠,但复杂
  • hashCode()相等的两个对象equal()不一定相等
  • 先比较hashcode再比较equal,效率高且可靠

1.4 面向对象

https://course.tianmaying.com/java-basic+abstract-class-and-interface#2
如果我们要定义的一个类没有足够的信息来描述一个具体的对象,还需要其他的具体类来支持,这个时候我们可以考虑使用抽象类(abstract)

1.4.1 抽象类、抽象方法、接口类、继承的概念

1.1).抽象类:类定义的前面增加 abstract 关键字,就表明一个类是抽象类

  • 类中至少包含了一个抽象(abstract)方法
  • 抽象类不能实例化对象,即无法通过new Graph()来创建对象, 也无法直接;
  • 抽象类必须被继承(extends),才能被实例化使用,由于抽象类不能实例化对象;
  • 类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样
  • 在抽象类中可以为部分方法提供默认的实现,避免在子类中重复实现;但java抽象类不支持多继承

1.2).抽象方法:abstract声明抽象方法,

  • 抽象方法只包含方法名,没有方法体,没有定义,方法名后直接跟一个分号,而不是花括号
  • 如果一个类包含抽象方法,那么该类必须是抽象类
  • 任何子类必须重写父类的抽象方法,否则就必须声明自身为抽象类

1.3).接口(可实现多个接口):类定义的前面增加 Interface 关键字,就表明一个类是接口类

  • 接口是一组抽象方法的集合,类中方法都是抽象方法
    • jdk1.8后可以有default默认实现方法、static静态方法
  • 接口在某种意义上是特殊的抽象类,所有的东西都是抽象的
  • 接口也和抽象类一样,无法被实例化,但是可以被实现(implements)
  • 接口的实现类,必须实现接口内所有方法,否则就必须声明为抽象类
    • jdk1.8后,因为接口可以有default默认方法实现,所以可以不必须实现所有接口中的抽象方法
  • 接口支持多重实现,即一个类可以同时实现多个接口
  • 接口中的方法是不能为静态static的
    • jdk1.8后可以有default默认实现方法、static静态方法
  • 接口中可声明变量,一般是final和static类型,要以常量初始化,实现类不能改变接口中的变量
  • 接口访问权限有:接口类可以是public权限和默认权限,若接口的访问权限是public,其方法和变量都是public
  • 接口类型变量,可以引用到一个该接口的实现类的对象, 例如:
Map<String,object> map = new HashMap<String,Object>();  
List<String> list = new ArrayList<String> ();  

2).继承: extends(java 只能单继承)

  • 1).Java中的继承是单继承的,也就是说一个子类只能继承一个父类。
  • 2).子类会继承父类中的除构造函数以外的所有非private成员方法,以及所有非private成员变量。
  • 3).生成子类实例时,Java默认先调用父类的无参构造方法,再调用子类构造方法,生成子类对象。
  • 4).this表示对当前对象的引用,而super表示对父类对象的引用。
  • 5).在子类的构造函数中,一般第一条语句是super();,表示调用父类构造函数。也可以调用父类有参数的构造函数,比如super(name);。
  • 6).若一个类的构造函数的第一语句既不是this()也不是super()时,就会隐含的调用super()。

作用:(1)代码复用;(2)建立抽象层次,更容易扩展

3).多态
父类的引用指向子类对象:父类类型 引用名称 = new 子类类型

多态成员变量

当子类中出现同名的成员变量时,多态调用该变量时:  
编译时期:参考的是引用型变量所属的类中是否有被调用的成员变量。没有,编译失败。  
运行时期:也是调用引用型变量所属的类中的成员变量。  
也就是编译和运行都参考等号的左边  

多态成员方法

  • 编译时期:参考引用变量所属的类,如果类中没有调用的方法。编译失败。
  • 运行时期:参考引用变量所指的对象所属的类,并运行对象所属类中的成员方法。
  • 也就是编译看左边(父类是否拥有该方法),运行看右边(静态都看左边)

执行 new Sub();
在创造子类的过程中首先创建父类对象,然后才能创建子类。
创建父类即默认调用Base()方法,在方法中调用callName()方法,由于子类中存在此方法,则被调用的callName()方法是子类中的方法,此时子类还未构造,所以变量baseName的值为null

先成员变量再构造方法,先父类再子类

多态表现:有同名方法执行子类的

执行 Base b = new Sub();时,由于多态编译时表现为Base类特性,运行时表现为Sub类特性,不管是哪种状态都会调用Base构造器执行 callName()方法;
执行方法时,由于多态表现为子类特性,所以会先在子类是否有 callName();而此时子类尚未初始化(执行完父类构造器后才会开始执行子类),如果有 就 执行(此时, 因为还没有调用子类构造函数, 所以子类的 baseName 输出为 null),没有再去父类寻找。

4).封装
其核心思想就是隐藏不需要对外公开的属性和方法,以减少对外耦合,包证数据的安全和程序的稳定。

Java访问权限关键字:

本类内部 本包 子类 外部包  
public
protected ×
default × ×
private × × ×

说明:Java访问权限控制是在编译层,不会再类文件中留下痕迹。通过反射机制,还是可以访问类的私有成员。

1.4.2 抽象类和接口类的异同点

相同点:

都不能被实例化

  • 1.都包含抽象方法,用于描述系统能提供哪些服务,而这些服务是由子类来提供实现的
  • 2.设计上,两者都代表系统的抽象层,当使用一棵继承树上的类时,应尽量把引用变量声明为继承树的上层抽象类型,

这样可以提高两个系统之间的松耦合

不同点:

  • 抽象类可以为部分方法提供默认实现,避免在子类中重复实现;接口不能提供任何方法的实现
  • 抽象类不支持多继承,但是接口支持多继承(实现多个接口)。
  • 接口代表了接口定义者和接口实现者的一种契约;而抽象类和具体类一般而言是一种继承关系;

1.4.3 类继承(单继承)和接口继承(可多继承)

  • java类是单继承的。classB Extends classA
  • java接口可以多继承。Interface3 Extends Interface0, Interface1, interface……

不允许类多重继承的主要原因是,如果A同时继承B和C,而B和C同时有一个D方法,A如何决定该继承那一个呢?

但接口不存在这样的问题,接口全都是抽象方法继承谁都无所谓,所以接口可以继承多个接口。

1.4.4 static、final

1.static :
成员变量前加static修饰符外,我们还可以在成员方法前加修饰符,表明该方法与某个具体实例无关,仅仅是该类的一个公共方法。

声明成static的方法有几条限制:

  • 仅能调用其他的static方法。
  • 只能访问static数据。
  • 不能以任何方式引用this或super
  • 静态方法可以直接通过类名调用,任何的该类的实例也都可以调用它的静态方法,因此静态方法中不能用this和super关键字。

JAVA中STATIC{}语句块详解:
static{}(即static块),会在类被加载的时候执行且仅会被执行一次,
一般用来初始化静态变量和调用静态方法

2.final
变量声明为final,目的是阻止它的内容被修改。这意味着在声明final变量的时候,必须初始化它

  • 被final修饰的方法可以被子类继承,不能被子类的方法覆盖
  • final定义的类不能继承,而abstract抽象类,需要继承 ,不可共存
  • final不能修饰构造方法。
  • 父类中的private成员方法是不能被子类覆盖的,所有有private限制的成员方法默认也是final的

使用final修饰方法除了不想让子类覆盖之外,还有一个原因就是高效,Java编译器在遇到final关键字修饰的方法时会使用内联机制,省去函数调用的开销,大大提高执行效率。
final变量的所有字符选择大写是一个普遍的编码约定,用final修饰的变量在实例中不占用内存,它实质上是一个常数

1.4.5 类加载、类实例化过程

类加载:
Java命令的作用是启动虚拟机,虚拟机通过输入流,从磁盘上将字节码文件(.class文件)中的内容读入虚拟机,并保存起来的过程就是类加载。

类加载特性 :

*在虚拟机的生命周期中一个类只被加载一次。  
*类加载的原则:延迟加载,能少加载就少加载,因为虚拟机的空间是有限的。  
*类加载的时机:  
    1)第一次创建对象要加载类.  
    2)调用静态方法时要加载类,访问静态属性时会加载类。  
    3)加载子类时必定会先加载父类。  
    4)创建对象引用不加载类.  
    5) 子类调用父类的静态方法时  
        (1)当子类没有覆盖父类的静态方法时,只加载父类,不加载子类  
        (2)当子类有覆盖父类的静态方法时,既加载父类,又加载子类  
    6)访问静态常量,如果编译器可以计算出常量的值,则不会加载类,  
        例如:public static final int a =123;否则会加载类,例如:public static final int a = math.PI。  

类的实例化过程:

JVM读取指定classpath路径下的class文件,加载到内存,如果有直接父类,也会加载父类;
堆内存分配空间;
执行父类、子类静态代码块;
对象属性进行默认初始化;
调用构造方法;
在构造方法中,先调用父类构造方法初始化父类数据;
初始化父类数据后,显示初始化,执行子类的构造代码块;
再进行子类构造方法的特定初始化;
初始化完毕后,将地址赋值给引用。

1.5 注解

1.5.1.注解定义:

注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。
它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

1.5.2.作用分类:

  • 编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】
  • 代码分析:通过代码里标识的元数据对代码进行分析【使用反射】
  • 编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】

1.5.3.常见注解:

  • @Override
    它的作用是对覆盖超类中方法的方法进行标记,如果被标记的方法并没有实际覆盖超类中的方法,则编译器会发出错误警告。
  • @SuppressWarnings
    deprecation,使用了过时的类或方法时的警告unchecked,执行了未检查的转换时的警告
    fallthrough,当 Switch 程序块直接通往下一种情况而没有 Break 时的警告
    path,在类路径、源文件路径等中有不存在的路径时的警告
    serial,当在可序列化的类上缺少 serialVersionUID 定义时的警告
    finally ,任何 finally 子句不能正常完成时的警告 all,关于以上所有情况的警告
  • @Deprecated
    @Deprecated的作用是对不应该在使用的方法添加注释,当编程人员使用这些方法时,将会在编译时显示提示信息,它与javadoc里的 @deprecated标记有相同的功能,准确的说,它还不如javadoc@deprecated,因为它不支持参数

1.5.4.@PostConstruct与@PreDestroy详解

Java EE5 引入了@PostConstruct和@PreDestroy这两个作用于Servlet生命周期的注解,实现Bean初始化之前和销毁之前的自定义操作

API使用说明

以下为@PostConstruct的API使用说明:
PostConstruct 注释用于在依赖关系注入完成之后需要执行的方法上,以执行任何初始化。
此方法必须在将类放入服务之前调用。支持依赖关系注入的所有类都必须支持此注释。即使类没有请求注入任何资源,用 PostConstruct 注释的方法也必须被调用。只有一个方法可以用此注释进行注释。

应用 PostConstruct 注释的方法必须遵守以下所有标准:

  • 该方法不得有任何参数,除非是在 EJB 拦截器 (interceptor) 的情况下,根据 EJB规范的定义,在这种情况下它将带有一个 InvocationContext 对象 ;
  • 该方法的返回类型必须为 void;该方法不得抛出已检查异常;
  • 应用 PostConstruct 的方法可以是 public、protected、package private 或 private ;
  • 除了应用程序客户端之外,该方法不能是 static;该方法可以是 final;
  • 如果该方法抛出未检查异常,那么不得将类放入服务中,除非是能够处理异常并可从中恢复的 EJB。

总结为一下几点:

  • 只有一个方法可以使用此注释进行注解;
  • 被注解方法不得有任何参数;
  • 被注解方法返回值为void;
  • 被注解方法不得抛出已检查异常;
  • 被注解方法需是非静态方法;
  • 此方法只会被执行一次;

Servlet执行流程图

两个注解加入只会,Servlet执行流程图:
在具体Bean的实例化过程中,@PostConstruct注释的方法,会在构造方法之后,init方法之前进行调用。

实例

基于Spring boot编写的可执行方法见github:https://github.com/HappySecondBrother/example UserService方法(提供缓存数据):

@Service
public class UserService {
    public List<String> getUser(){
        List<String> list = new ArrayList<>();
        list.add("张三");
        list.add("李四");
        return list;
    }
}

// BusinessService方法,通过@PostConstruct调用UserService:
@Service
public class BusinessService {
    @Autowired
    private UserService userService;
    private List<String> list = null;

    /**
     * 构造方法执行之后,调用此方法
     */
    @PostConstruct
    public void init(){
        System.out.println("@PostConstruct方法被调用");
        // 实例化类之前缓存获得用户信息
        List<String> list = userService.getUser();
        this.list = list;
        if(list != null && !list.isEmpty()){
            for(String user : list){
                System.out.println("用户:" + user);
            }
        }
    }
    public BusinessService(){
        System.out.println("构造方法被调用");
    }
    public List<String> getList() {
        return list;
    }
    public void setList(List<String> list) {
        this.list = list;
    }
}

执行结果:

构造方法被调用
@PostConstruct方法被调用
用户:张三
用户:李四

项目应用

在项目中@PostConstruct主要应用场景是在初始化Servlet时加载一些缓存数据等。

注意事项

使用此注解时会影响到服务的启动时间。服务器在启动时会扫描WEB-INF/classes的所有文件和WEB-INF/lib下的所有jar包。

1.5.5 @JsonFormat和@JSONField、@Transient 注解

  • @JSONField
    • @JSONField(ordinal =0) 序列化字段的顺序,默认是0
    • @JSONField(name = “”) 用于解决属性名和key不一致的情况,当前端传过来的字段名不一样的时候,我们可以在字段名上加上这个注解
    • @JSONField(format = “yyyy-MM-dd HH:mm:ss”) 用在Date属性上,自动格式化日期
    • @JSONField(serialize = false) 是否要把这个字段序列化成JSON字符串,默认是true
    • @JSONField(deserialize = false) 字段是否需要进行反序列化,默认是true
  • @JsonFormat
  • @Transient
    • 实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中,该变量内容在序列化后无法获得访问
    • 被transient修饰,变量将不再是对象持久化的一部分,不做库表的orm 映射处理

1.6 常用类库-工具包

  • Apache-commons
    • Betwixt: XML与Java对象之间相互转换。
    • Launcher: 可以跨平台独立启动的java应用程序。
    • Exec: 提供常用方法用来执行外部进程,如执行exe文件或命令行
    • Validator: 提供了在一个XML文件中定义校验器(校验方法)和校验规则
    • CLI:CLI 提供针对命令行参数,选项,选项组,强制选项等的简单API
    • Compress: 压缩、解压缩,可操作ar、cpio、Unix dump、tar、zip、gzip、XZ、Pack200和bzip2
    • Codec: 提供常用的编码和解码方法,如DES、SHA1、MD5、Base64、URL和Soundx等。
    • Configuration :java应用程序的配置管理类库,可以从properties或者xml文件中加载配置信息。
    • DBCP :提供数据库连接池服务。
    • DbUtils: 提供对jdbc 的操作封装来简化数据查询和记录读取操作。
    • Email: 邮件操作组件,对java Mail api进行封装,提供了常用的邮件发送和接收类
    • FileUpload: 为Web应用程序或Servlet提供文件上传功能,Struts2和SpringMVC的文件上传组件。
    • IO: io工具类包,对java.io扩展,提供更加方便的IO操作。
    • Lang:Java基本对象方法的工具类包,提供对字符、数组等基本对象的操作,StringUtils,ArrayUtils
    • Collections:扩展java标准Collections API.对常用的集合操作进行封装、抽象和补充
    • BeanUtils: 提供了对于JavaBean进行各种操作,克隆对象,属性等。
    • Net: 封装了各种网络协议的客户端,支持FTP、NNTP、SMTP、POP3、Telnet等协议。
    • Math :轻量级自容器的数学和统计计算方法类包,包含大多数常用的数值算法。
    • Logging: 提供统一的日志接口,同时兼顾轻量级和不依赖具体的实现。
    • Apache HttpClient: 曾是 Apache Commons的子项目,后独立 。HttpClient简化HTTP客户端与服务器的各种通讯,实现HTTP客户端程序(也就是浏览器程序)的功能
  • JDK:包位置 D:/java/jre/lib/rt.jar/java
    • java.lang:提供Java编程的基础类,如 Object、Math、String、StringBuffer、System、Thread等
    • java.util:提供了包含集合框架、遗留的集合类、事件模型、日期和时间实施、国际化和各种实用工具类(字符串标记生成器、随机数生成器和位数组)。
    • java.io:该包通过文件系统、数据流和序列化提供系统的输入与输出。
    • java.Math:数学运算相关
    • java.net:该包提供实现网络应用与开发的类。
    • Java.nio :为输入输出提供缓冲区的类
    • java.sql:提供了使用Java语言访问并处理存储在数据源(数据库)中的数据API。
    • java.awt: 提供了创建界面和绘制图形图像的所有类,提供了GUI设计与开发的类
    • javax.swing:提供了GUI设计与开发的类。而javax.swing包提供了一组“轻量级”的组件
    • java.text: 提供了与自然语言无关的方式来处理文本、日期、数字和消息的类和接口。
    • Java.applet:提供创建applet小程序所需要的类
    • Java.beans:包含与开发javaBeans相关的类

使用总结

equals()和hashCode()

首先equals()和hashCode()方法、包括toString()方法=都可以由IDEA工具生成,属于模板代码

  • https://blog.csdn.net/u012133048/article/details/87878586
  • https://blog.csdn.net/javazejian/article/details/51348320
  • https://blog.csdn.net/qq_28051453/article/details/52701171

数据转换

#### byte-String
1.String转byte数组:
String str = "abcd";
byte[] bs = str.getBytes();

2.byte数组转String:  
String s = new String(bs,"utf-8");

#### Array-List 
1.如果你的List只是用来遍历,就用Arrays.asList()吧!  
例:String转数组,再转list
Arrays.asList(StringUtils.split(stringObj, ","))

这个ArrayList不是java.util包下的,而是java.util.Arrays.ArrayList,显然它是Arrays类自己定义的一个内部类!这个内部类没有实现add()、remove()方法,而是直接使用它的父类AbstractList的相应方法。而AbstractList中的add()和remove()是直接抛出java.lang.UnsupportedOperationException异常的!

2.如果你的List还要添加或删除元素,还是乖乖地new一个java.util.ArrayList,然后一个一个的添加元素吧!
//Collections.addAll()
String[] array = {“aa”,”bb”,”cc”}; 
List List = new ArrayList(); 
Collections.addAll(List, array); 

//循环遍历数组,add到list中
for(int i = 0; i < array.length; i++){
    List.add(array[i]);
}

#### String-int 
1.String 转 int
int a = Integer.parseInt(str);
int b = Integer.valueOf(str).intValue()

2. int转 String
//注: Double, Float, Long 的方法大同小异.
String str = String.valueOf(int i);
String str = Integer.toString(int i);
String str = “” + i ;

#### map-obj 
1.map转obj 

2.obj转map

#### Date  
1.date转String
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");//日期格式
string date = sdf.format(new Date());

2.String转date
String string = "2014-3-17";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
date = sdf .parse(string);

#### JsonObject & JSONArray
1.jsonString转jsonObject,遍历键值对
JSONObject data = JSONObject.parseObject(param);//com.alibaba.fastjson.JSON
JSONObject jsonParams = JSONObject.fromObject(queryParams);//net.sf.json.JSONObject
Iterator<String> paramKeys = jsonParams.keys(); 
        while(paramKeys.hasNext()){
            String paramName = paramKeys.next(); 
           String value = jsonParams.getString(paramName)
        )

2.Map转jsonObject
Map<String, Object> rtn = new HashMap<String, Object>(); 
JSONObject json = JSONObject.fromObject(rtn);  //net.sf.json.JSONObject

3.Object转jsonObject
JSONObject data = JSONObject.parseObject(param);//com.alibaba.fastjson.JSON
JSONObject jsonParams = JSONObject.fromObject(queryParams);//net.sf.json.JSONObject

4.JSONObject 转 Map/object
JSONObject.parseObject(result.toString(), Map.class);

6.JSONArray 转 List<T>  
//net.sf.json.JSONArray
List<TJzglWj> wj = (List<TJzglWj>)JSONArray.toCollection(jsonArray2,TJzglWj.class);

7.jsonString 转 List<T>  
//com.alibaba.fastjson.JSON
List<TJzglWj> parseArray = JSON.parseArray(listStr, TJzglWj.class);

#### Spring BeanUtils 的对象复制 copyProperties
BeanUtils.copyproperties(source,target)

#### 求商-保留两位小数
private String divideBy2Decimal(double numA, double numB){
    if(numB == 0.00){
        return "0";
    }
    BigDecimal bigDecimalNumA = BigDecimal.valueOf(numA);
    BigDecimal bigDecimalNumB = BigDecimal.valueOf(numB);
    BigDecimal result = bigDecimalNumA.divide(bigDecimalNumB, 2, BigDecimal.ROUND_HALF_UP);
    return result.toString();
}

stream示例

https://blog.csdn.net/lu930124/article/details/77595585

1.stream优雅的去重
字符串集合去重
List<String> distinctElements = list.stream().distinct().collect(Collectors.toList());

// 根据属性id去重
List<Person> unique = appleList.stream().collect( 
    collectingAndThen(
        toCollection(  () -> new TreeSet<>(comparingLong(Apple::getId))  ), 
        ArrayList::new
    ) 
); 

根据对象属性去重
public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
    Map<Object, Boolean> map = new ConcurrentHashMap<>();
    return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
//使用举例
persons.stream().filter(distinctByKey(Person::getName))

2.groupingBy():list 分组转 Map<String, List<Student>>
Map<String, List<Student>> stuentMap = studentList.stream().collect(Collectors.groupingBy(Student::getName()));
Map<String, List<Map<String, Object>>> AttendanceLeaveRegisterMap = AttendanceLeaveRegisterMapList.stream().collect(Collectors.groupingBy(e -> e.get("user_id").toString()));

3.sorted()排序
List<StudentInfo> studentsSortName = studentList.stream().sorted(Comparator.comparing(StudentInfo::getAge)).collect(Collectors.toList());

4.filter() 过滤
List<StaffWithDept> deptStaffs = staffWithDepts.stream().filter(s -> deptId.equals(s.getDeptId())).collect(Collectors.toList());

5.map() 使用
List<Integer> deptIds = staffWithDepts.stream().map(StaffWithDept::getDeptId).distinct().collect(Collectors.toList());//选出去重后的部门id

6.List转Map
//需要注意的是: toMap 如果集合对象有重复的key,会报错Duplicate key .... apple1,apple12的id都为1。可以用 (k1,k2)->k1 来设置,如果有重复的key,则保留key1,舍弃key2
Map<Integer, Apple> appleMap = appleList.stream().collect(Collectors.toMap(Apple::getId, a -> a,(k1,k2)->k1));

7.求和:将集合中的数据按照某个属性求和
//计算 总金额
BigDecimal totalMoney = appleList.stream().map(Apple::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);

8.查找流中最大 最小值 Collectors.maxBy 和 Collectors.minBy 
Optional<Dish> maxDish = Dish.menu.stream().collect(Collectors.maxBy(Comparator.comparing(Dish::getCalories)));
Optional<Dish> minDish = Dish.menu.stream().collect(Collectors.minBy(Comparator.comparing(Dish::getCalories)));

Post Directory

扫码关注公众号:暂无公众号
发送 290992
即可立即永久解锁本站全部文章