JAVA JDK 常用工具类和工具方法

目录

Pair与Triple

Lists.partition-将一个大集合分成若干

List集合操作的轮子

对象工具Objects 与ObjectUtils

字符串工具

MapUtils

Assert断言

switch语句

三目表达式

IOUtils

MultiValueMap

MultiMap 

JAVA各个时间类型的转换(LocalDate与Date类型)


Pair与Triple

org.apache.commons.lang3 提供了返回多个值的工具类,返回2个值用Pair,3个值Triple

当我们想从方法中返回两个值或者三个值时

Pair的介绍

配对(Pair)。配对提供了一种方便方式来处理简单的键值关联,当我们想从方法中返回两个值时特别有用。

当涉及到key-value键值对时,我们一般使用Map映射去做处理,此时的key相当于value的一个描述或者引用,而具体的信息都保存在value中,我们可以通过key去获取对应的value。但是当key和value都保存具体信息时,我们就需要用到Pair对了。

实际上Pair保存的应该说是一个信息对,两个信息都是我们需要的,没有key和value之分。

注意:(特别适合用于在一个方法中返回两个值)

在核心Java库中可以使用配对(Pair)的实现。除此之外,某些第三方库,比如Apache Commons和Vavr,已经在各自的api中公开了这个功能。

Pair具体的用法

javafx.util包下的

有一个简单Pair类。

 public class Pair<K, V> implements Serializable {
    private K key;
    private V value;


    public K getKey() {
        return this.key;
    }


    public V getValue() {
        return this.value;
    }


    public Pair(@NamedArg("key") K var1, @NamedArg("value") V var2) {
        this.key = var1;
        this.value = var2;
    }
 }

Pair<String, String> pair = new Pair<>("aku", "female");
pair.getKey();
pair.getValue()

Apache Commons库中的Pair(一般用这个)

org.apache.commons.lang3.tuple 包中提供Pair抽象类,它有两个子类,分别代表不可变与可变配对:ImmutablePair 和 MutablePair。两者都实现了访问key/value以及setter和getter方法。

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.10</version>
</dependency>

public abstract class Pair<L, R> implements Map.Entry<L, R>, Comparable<Pair<L, R>>, Serializable {
 
  
    /**
     * @return 返回一个不可变的Pair对ImmutablePair
     */
    public static <L, R> Pair<L, R> of(final L left, final R right) {
        return new ImmutablePair<>(left, right);
    }
 
   
    public abstract L getLeft();
 
    
    public abstract R getRight();
 
   
    @Override
    public final L getKey() {
        return getLeft();
    }
 
    
    @Override
    public R getValue() {
        return getRight();
    }
 
 
}

Pair<String, String> pair = Pair.of("aku", "female");
pair.getLeft();
pair.getRight();

Pair 中的不可变组件ImmutablePair与可变组件MutablePair

意义完全与Triple中的可变组件ImmutableTriple与不可变组件MutableTriple一致,建议参考后面的关于Triple中可变与不可变的概述

Pair 使用示例(一般使用里面的Of方法去初始化值)

/*
   过滤出,校验成功和失败的数据
  */
 public static Pair<List<Integer>, List<Integer>> checkData(List<Integer> list) {
     if (CollectionUtils.isNotEmpty(list)) {
         ArrayList<Integer> successList = new ArrayList<>();
         ArrayList<Integer> failList = new ArrayList<>();


         list.forEach((a) -> {
             if (a > 5) {
                 successList.add(a);
             } else {
                 failList.add(a);
             }
         });
         return Pair.of(successList, failList);
     } else {
         return Pair.of(null, null);
     }
 }


 /*
    过滤数据,失败的数据要有失败原因 -每一条数据一个Pair
*/
 public static List<Pair<Integer, String>> checkData2(List<Integer> list) {
     if (CollectionUtils.isNotEmpty(list)) {
         List<Pair<Integer, String>> pairsList = new ArrayList<>();
         list.forEach((a) -> {
             if (a > 5) {
                 pairsList.add(Pair.of(a, null));
             } else {
                 pairsList.add(Pair.of(a, "数据小于5"));
             }
         });
         return pairsList;
     } else {
         return null;
     }
 }
 
public static void main(String[] args) {
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, -1);
    /*
      过滤出,校验成功和失败的数据
    */
    Pair<List<Integer>, List<Integer>> pair = checkData(list);
    List<Integer> successList = pair.getLeft();
    List<Integer> failList = pair.getRight();
    System.out.println("successList:" + successList + " failList:" + failList);
   /*
     过滤数据,失败的数据要有失败原因--每一条数据一个Pair
   */
    List<Pair<Integer, String>> pairsList = checkData2(list);
    List<Integer> successList2 = new ArrayList<>();
    List<Integer> failList2 = new ArrayList<>();
    if (CollectionUtils.isNotEmpty(pairsList)) {
        //遍历每个pair
        for (Pair<Integer, String> myPair : pairsList) {
            //有失败原因代表是失败的数据
            if (StringUtils.isNotEmpty(myPair.getRight())) {
                failList2.add(myPair.getLeft());
            } else {
                successList2.add(myPair.getLeft());
            }
        }
    }
    System.out.println("successList2:" + successList2 + " failList2:" + failList2);
}

打印结果

successList:[6, 7, 8, 9] failList:[1, 2, 3, 4, 5, 0, -1]

successList2:[6, 7, 8, 9] failList2:[1, 2, 3, 4, 5, 0, -1]

Triple

org.apache.commons.lang3 提供了返回多个值的工具类,返回2个值用Pair,3个值Triple

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.10</version>
</dependency>

Triple中的源码

Triple抽象类源码

一般使用里面的Of方法去初始化Triple中的三个值

package org.apache.commons.lang3.tuple;
import java.io.Serializable;
import java.util.Objects;


import org.apache.commons.lang3.builder.CompareToBuilder;


public abstract class Triple<L, M, R> implements Comparable<Triple<L, M, R>>, Serializable {


    /** Serialization version */
    private static final long serialVersionUID = 1L;


    /**
     * 静态方法,返回不可变的存储三个元素的组件对象
     */
    public static <L, M, R> Triple<L, M, R> of(final L left, final M middle, final R right) {
        return new ImmutableTriple<>(left, middle, right);
    }


    /**
     * 获取 左元素
     */
    public abstract L getLeft();


    /**
     * 获取中元素
     */
    public abstract M getMiddle();


    /**
     * 获取右元素
     */
    public abstract R getRight();


    /**
     * 比较组件中三个元素的值大小
     */
    @Override
    public int compareTo(final Triple<L, M, R> other) {
      return new CompareToBuilder().append(getLeft(), other.getLeft())
          .append(getMiddle(), other.getMiddle())
          .append(getRight(), other.getRight()).toComparison();
    }


    /**
     * 比较三个组件中三个对象值是否相等
     */
    @Override
    public boolean equals(final Object obj) {
        if (obj == this) {
            return true;
        }
        if (obj instanceof Triple<?, ?, ?>) {
            final Triple<?, ?, ?> other = (Triple<?, ?, ?>) obj;
            return Objects.equals(getLeft(), other.getLeft())
                && Objects.equals(getMiddle(), other.getMiddle())
                && Objects.equals(getRight(), other.getRight());
        }
        return false;
    }


    /**
     * 返回组件对象的哈希吗
     */
    @Override
    public int hashCode() {
        return (getLeft() == null ? 0 : getLeft().hashCode()) ^
            (getMiddle() == null ? 0 : getMiddle().hashCode()) ^
            (getRight() == null ? 0 : getRight().hashCode());
    }


    /**
     * 打印组件的三个对象
     */
    @Override
    public String toString() {
        return "(" + getLeft() + "," + getMiddle() + "," + getRight() + ")";
    }


    /**
     * 格式化三个组件的对象
     */
    public String toString(final String format) {
        return String.format(format, getLeft(), getMiddle(), getRight());
    }


}

Triple的实现类1 ImmutableTriple不可变组件对象

package org.apache.commons.lang3.tuple;


public final class ImmutableTriple<L, M, R> extends Triple<L, M, R> {


    /**
    * 返回一个三个对象都是null的不可变组件
    */
    @SuppressWarnings("rawtypes")
    private static final ImmutableTriple NULL = ImmutableTriple.of(null, null, null);


    /** Serialization version */
    private static final long serialVersionUID = 1L;


    /**
    * 静态方法,返回三个元素都为null的不可变的组件对象
    */  
    @SuppressWarnings("unchecked")
    public static <L, M, R> ImmutableTriple<L, M, R> nullTriple() {
        return NULL;
    }


    /** Left object */
    public final L left;
    /** Middle object */
    public final M middle;
    /** Right object */
    public final R right;


    /**
     * 静态方法,返回一个三个指定对象的组件对象
     */
    public static <L, M, R> ImmutableTriple<L, M, R> of(final L left, final M middle, final R right) {
        return new ImmutableTriple<>(left, middle, right);
    }


    /**
     * 传递三个对象的构造函数
     */
    public ImmutableTriple(final L left, final M middle, final R right) {
        super();
        this.left = left;
        this.middle = middle;
        this.right = right;
    }


    /**
     * 返回做元素
     */
    @Override
    public L getLeft() {
        return left;
    }


    /**
     * 返回中间元素
     */
    @Override
    public M getMiddle() {
        return middle;
    }


    /**
     * 返回右元素
     */
    @Override
    public R getRight() {
        return right;
    }
}

ImmutableTriple的不可变是指什么

(Pair中的不可变对象ImmutablePair意义与ImmutableTriple完全一致)

不可变是指,一旦初始化了Triple中的三个属性值(左中右)就无法重新设置这三个属性值了,但是我们可以通过改变赋值给Triple中的三个属性的那些对象从而去间接改变Triple中的值,因为Triple中的三个属性值如果存储的是对象的话,仅仅是存储这些对象的引用,我们直接去改变这些对象就可以间接改变Triple中的值

但是如果Triple中的三个属性值如果存储的是基本类型,或者包装类如Int,interger,String,就无法通过这种方式去间接改变Triple中的值。

示例如下

public class TestMain {
    public static void main(String[] args) {
        User user1 = new User();
        User user2 = new User();
        User user3 = new User();
        user1.setId(1L);
        user2.setId(2L);
        user3.setId(3L);
        //1 测试普通的对象
        Triple<User, User, User> of = Triple.of(user1, user2, user3);
        user1.setId(3L);
        user2.setId(4L);
        user3.setId(5L);
        System.out.println("left:"+of.getLeft()+"middle:"+of.getMiddle()+"right:"+of.getRight());
        //测试基本类型int
        int a=1;
        int b=2;
        int c=3;
        Triple<Integer, Integer, Integer> of1 = Triple.of(a, b, c);
        a=4;
        b=5;
        c=3;
        System.out.println("left:"+of1.getLeft()+"middle:"+of1.getMiddle()+"right:"+of1.getRight());
        //测试包装类型Integer
        Integer aa=11;
        Integer bb=22;
        Integer cc=33;
        Triple<Integer, Integer, Integer> of2 = Triple.of(aa, bb, cc);
        aa=44;
        bb=55;
        cc=66;
        System.out.println("left:"+of2.getLeft()+"middle:"+of2.getMiddle()+"right:"+of2.getRight());


        //测试基本类型String
        String aaa="11";
        String bbb="22";
        String ccc="33";
        Triple<String, String, String> of3 = Triple.of(aaa, bbb, ccc);
        aaa="44";
        bbb="55";
        ccc="66";
        System.out.println("left:"+of3.getLeft()+"middle:"+of3.getMiddle()+"right:"+of3.getRight());
    }


}


//测试结果
left:User(id=3, name=null, pwd=null, headImg=null, slogan=null, sex=null, points=null, createTime=null, mail=null, secret=null)
middle:User(id=4, name=null, pwd=null, headImg=null, slogan=null, sex=null, points=null, createTime=null, mail=null, secret=null)
right:User(id=5, name=null, pwd=null, headImg=null, slogan=null, sex=null, points=null, createTime=null, mail=null, secret=null)




left:1 middle:2 right:3
left:11 middle:22 right:33
left:11 middle:22 right:33

Triple的实现类2 -MutableTriple可改变值的三个元素组件对象

MutableTriple的可变是指MutableTriple中提供了setLeft,setRight等方法直接去修改Triple中值

(Pair中的可变对象MutablePair意义与ImmutableTriple完全一致)

package org.apache.commons.lang3.tuple;
public class MutableTriple<L, M, R> extends Triple<L, M, R> {


    /** Serialization version */
    private static final long serialVersionUID = 1L;


    /** Left object */
    public L left;
    /** Middle object */
    public M middle;
    /** Right object */
    public R right;


    /**
     * 静态方法,返回三个元素对象的组件对象
     */
    public static <L, M, R> MutableTriple<L, M, R> of(final L left, final M middle, final R right) {
        return new MutableTriple<>(left, middle, right);
    }


    /**
     * 无参数构造函数
     */
    public MutableTriple() {
        super();
    }


    /**
     * 三个参数的构造函数
     */
    public MutableTriple(final L left, final M middle, final R right) {
        super();
        this.left = left;
        this.middle = middle;
        this.right = right;
    }


    /**
     * 返回左元素
     */
    @Override
    public L getLeft() {
        return left;
    }


    /**
     * 返回右元素
     */
    public void setLeft(final L left) {
        this.left = left;
    }


    /**
     * 返回中间元素
     */
    @Override
    public M getMiddle() {
        return middle;
    }


    /**
     * 修改中间对象值
     */
    public void setMiddle(final M middle) {
        this.middle = middle;
    }


    /**
     * 返回右元素 值
     */
    @Override
    public R getRight() {
        return right;
    }


    /**
     * 修改右元素对象值
     */
    public void setRight(final R right) {
        this.right = right;
    }
}

Triple的使用示例(一般使用里面的Of方法去初始化值)

import org.apache.commons.lang3.tuple.ImmutableTriple;
import org.apache.commons.lang3.tuple.Triple;


public class Test  {
    public static void main(String[] args) {
        Triple triple = new ImmutableTriple("张三", 11,"男");
        System.out.println(triple.getLeft());
        System.out.println(triple.getMiddle());
        System.out.println(triple.getRight());


        String aaa="11";
        String bbb="22";
        String ccc="33";
        Triple<String, String, String> of3 = Triple.of(aaa, bbb, ccc);
       System.out.println("left:"+of3.getLeft()+"middle:"+of3.getMiddle()+"right:"+of3.getRight());


  }
}

Lists.partition-将一个大集合分成若干个小集合

将list集合按指定长度进行切分,返回新的List<List<??>>集合

引入相关依赖

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>21.0</version>
</dependency>

List<Integer> list = Lists.newArrayList(1, 2, 3, 4, 5);


List<List<Integer>> partitionList = Lists.partition(list, 2);


System.out.println(partitionList);

执行结果:

[[1, 2], [3, 4], [5]]

这个例子中,list有5条数据,我将list集合按大小为2,切分成了3个小集合。

使用场景:

1 这个方法在分批操作中非常有用,如分批查询,分批调用

比如有个需求:现在有5000个id,需要调用批量用户查询接口,查出用户数据。但如果你直接查5000个用户,单次接口响应时间可能会非常慢。如果改成分批处理,每次只查500个用户,异步调用10次接口,就不会有单次接口响应慢的问题。

BigDecimal

Java之BigDecimal详解 - HuaToDevelop - 博客园 (cnblogs.com)

BigDecimal的简介

​ Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。

双精度浮点型变量double可以处理16位有效数(最多16位),但在实际应用中,可能需要对更大或者更小精度的数进行运算和处理一般情况下,对于那些不需要准确计算精度的数字,我们可以直接使用Float和Double处理,但是Double.valueOf(String) 和Float.valueOf(String)会丢失精度

所以开发中,如果我们需要精确计算的结果,则必须使用BigDecimal类来操作。

BigDecimal(它不是一个基本类型),故我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。

BigDecimal常用构造函数

BigDecimal(int)

创建一个具有参数所指定整数值的对象

BigDecimal(double)

创建一个具有参数所指定双精度值的对象

BigDecimal(long)

创建一个具有参数所指定长整数值的对象

BigDecimal(String)--最好只用这种构造函数

创建一个具有参数所指定以字符串表示的数值的对象

最好只用这种构造函数去创建BigDecimal,否则一些BigDecimal的函数的执行结果可能不符合预期

以上构造函数的使用问题分析

        BigDecimal a =new BigDecimal(0.1);
        System.out.println("a values is:"+a);
        System.out.println("=====================");
        BigDecimal b =new BigDecimal("0.1");
        System.out.println("b values is:"+b);
        BigDecimal c =new BigDecimal(1.0);
        System.out.println("c values is:"+c);
        BigDecimal d =new BigDecimal(1);
        System.out.println("d values is:"+d);

结果示例:

a values is:0.1000000000000000055511151231257827021181583404541015625
=====================
b values is:0.1
c values is:1
d values is:1

原因分析:

1)参数类型为double的构造方法的结果有一定的不可预知性。有人可能认为在Java中写入newBigDecimal(0.1)所创建的BigDecimal正好等于 0.1(非标度值 1,其标度为 1),但是它实际上等于0.1000000000000000055511151231257827021181583404541015625。这是因为0.1无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数)。这样,传入到构造方法的值不会正好等于 0.1(虽然表面上等于该值)。

2)String 构造方法是完全可预知的:写入 newBigDecimal(“0.1”) 将创建一个 BigDecimal,它正好等于预期的 0.1。因此,比较而言, 通常建议优先使用String构造方法。

3)当double必须用作BigDecimal的源时,请注意,此构造方法提供了一个准确转换;它不提供与以下操作相同的结果:先使用Double.toString(double)方法,然后使用BigDecimal(String)构造方法,将double转换为String。要获取该结果,请使用static valueOf(double)方法。

BigDecimal常用方法详解

add(BigDecimal)

两个BigDecimal对象中的值相加,返回BigDecimal对象

subtract(BigDecimal)

两个BigDecimal对象中的值相减,返回BigDecimal对象

multiply(BigDecimal)

两个BigDecimal对象中的值相乘,返回BigDecimal对象

divide(BigDecimal)

两个BigDecimal对象中的值相除,返回BigDecimal对象

除法的时候出现异常

java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result

原因分析:

​ 通过BigDecimal的divide方法进行除法时当不整除,出现无限循环小数时,就会抛异常:java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

解决方法:

​ divide方法设置精确的小数点,如:divide(xxxxx,2)

toString()

将BigDecimal对象中的值转换成字符串

doubleValue()

将BigDecimal对象中的值转换成双精度数

floatValue()

将BigDecimal对象中的值转换成单精度数

longValue()

将BigDecimal对象中的值转换成长整数

intValue()

将BigDecimal对象中的值转换成整数

setScale()处理BigDecimal的小数点

#newScale表示留下几位小数,roundingMode表示小数点的保留模式
public BigDecimal setScale(int newScale, RoundingMode roundingMode) {
    return setScale(newScale, roundingMode.oldMode);
}

1 setScale(1,BigDecimal.ROUND_DOWN)直接删除多余的小数位,如2.35会变成2.3适用于构造方法参数是String类型

2 setScale(1,BigDecimal.ROUND_UP)进位处理,(留下的最后一位小数会进一位)-适用于构造方法参数是String类型

如2.35变成2.4 如2.34也会变成2.4

3 setScale(1,BigDecimal.ROUND_HALF_UP)四舍五入, (向上取舍)(也叫5舍6入)-适用于构造方法参数是String类型

如 2.35变成2.4 , 2.34 变成2.3

4 setScaler(1,BigDecimal.ROUND_HALF_DOWN)四舍五入(向下取舍)(也叫5舍6入)-适用于构造方法参数是String类型

如2.35变成2.3 ,2.36 变成2.4

BigDecimal bigDecimal = new BigDecimal("2.35").setScale(1,BigDecimal.ROUND_HALF_DOWN);
BigDecimal bigDecimal2 = new BigDecimal("2.36").setScale(1,BigDecimal.ROUND_HALF_DOWN);
System.out.println(bigDecimal1);
System.out.println(bigDecimal2);
//2.3
//2.4

compareTo-比较两个BigDecimal 的大小

java中对BigDecimal比较大小一般用的是bigdemical的compareTo方法

int a = bigdemical.compareTo(bigdemical2)

返回结果分析:

a = -1,表示bigdemical小于bigdemical2;
a = 0,表示bigdemical等于bigdemical2;
a = 1,表示bigdemical大于bigdemical2;

举例:a大于等于b

new bigdemica(a).compareTo(new bigdemical(b)) >= 0

BigDecimal格式化(NumberFormat与DecimalFormat的使用)-重点

由于NumberFormat类的format()方法可以使用BigDecimal对象作为其参数,可以利用BigDecimal对超出16位有效数字的货币值,百分值,以及一般数值进行格式化控制。

以利用BigDecimal对货币和百分比格式化为例。首先,创建BigDecimal对象,进行BigDecimal的算术运算后,分别建立对货币和百分比格式化的引用,最后利用BigDecimal对象作为format()方法的参数,输出其格式化的货币值和百分比。

    NumberFormat currency = NumberFormat.getCurrencyInstance(); //建立货币格式化引用 
    NumberFormat percent = NumberFormat.getPercentInstance();  //建立百分比格式化引用 
    percent.setMaximumFractionDigits(3); //百分比小数点最多3位 
    
    BigDecimal loanAmount = new BigDecimal("15000.48"); //贷款金额
    BigDecimal interestRate = new BigDecimal("0.008"); //利率   
    BigDecimal interest = loanAmount.multiply(interestRate); //相乘
 
    System.out.println("贷款金额:\t" + currency.format(loanAmount)); 
    System.out.println("利率:\t" + percent.format(interestRate)); 
    System.out.println("利息:\t" + currency.format(interest)); 

结果:

贷款金额: ¥15,000.48 利率: 0.8% 利息: ¥120.00

BigDecimal格式化保留2为小数,不足则补0:

public class myNumberFormat {
	
	public static void main(String[] s){
		System.out.println(formatToNumber(new BigDecimal("3.435")));
		System.out.println(formatToNumber(new BigDecimal(0)));
		System.out.println(formatToNumber(new BigDecimal("0.00")));
		System.out.println(formatToNumber(new BigDecimal("0.001")));
		System.out.println(formatToNumber(new BigDecimal("0.006")));
		System.out.println(formatToNumber(new BigDecimal("0.206")));
    }
    
/**
 * @desc 
 * 1.   0~1之间的BigDecimal小数,格式化后失去前面的0,则前面直接加上0。
 * 2.  传入的参数等于0,则直接返回字符串"0.00"
 * 3.  大于1的小数,直接格式化返回字符串
 * @param
 * @return
 */
	public static String formatToNumber(BigDecimal obj) {
		DecimalFormat df = new DecimalFormat("#.00");
		if(obj.compareTo(BigDecimal.ZERO)==0) {
			return "0.00";
		}else if(obj.compareTo(BigDecimal.ZERO)>0&&obj.compareTo(new BigDecimal(1))<0){
			return "0"+df.format(obj).toString();
		}else {
			return df.format(obj).toString();
		}
	}
}

结果为:

3.44
0.00
0.00
0.00
0.01
0.21

BigDecimal常见异常

除法的时候出现异常

java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result

原因分析:

​ 通过BigDecimal的divide方法进行除法时当不整除,出现无限循环小数时,就会抛异常:java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

解决方法:

​ divide方法设置精确的小数点,如:divide(xxxxx,2)

BigDecimal总结--重点

总结

  1. 在需要精确的小数计算时再使用BigDecimal,BigDecimal的性能比double和float差,在处理庞大,复杂的运算时尤为明显。故一般精度的计算没必要使用BigDecimal。

  1. 尽量使用参数类型为String的构造函数。

--最好只用这种构造函数去创建BigDecimal,否则一些BigDecimal的函数的执行结果可能不符合预期

  1. BigDecimal都是不可变的(immutable)的, 在进行每一次四则运算时,都会产生一个新的对象 ,所以在做加减乘除运算时要记得要保存操作后的值。

BigDecimal的工具类--(自己写的)BigDecimalUtils--值得参考

/**
 * 用于高精确处理常用的数学运算
 */
public class BigDecimalUtils {
    //默认除法运算精度
    private static final int DEF_DIV_SCALE = 10;


    /**
     * 提供精确的加法运算
     *
     * @param v1 被加数
     * @param v2 加数
     * @return 两个参数的和
     */


    public static double add(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.add(b2).doubleValue();
    }


    /**
     * 提供精确的加法运算
     *
     * @param v1 被加数
     * @param v2 加数
     * @return 两个参数的和
     */
    public static BigDecimal add(String v1, String v2) {
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.add(b2);
    }


    /**
     * 提供精确的加法运算
     *
     * @param v1    被加数
     * @param v2    加数
     * @param scale 保留scale 位小数
     * @return 两个参数的和
     */
    public static String add(String v1, String v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.add(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
    }


    /**
     * 提供精确的减法运算
     *
     * @param v1 被减数
     * @param v2 减数
     * @return 两个参数的差
     */
    public static double sub(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.subtract(b2).doubleValue();
    }


    /**
     * 提供精确的减法运算。
     *
     * @param v1 被减数
     * @param v2 减数
     * @return 两个参数的差
     */
    public static BigDecimal sub(String v1, String v2) {
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.subtract(b2);
    }


    /**
     * 提供精确的减法运算
     *
     * @param v1    被减数
     * @param v2    减数
     * @param scale 保留scale 位小数
     * @return 两个参数的差
     */
    public static String sub(String v1, String v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.subtract(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
    }


    /**
     * 提供精确的乘法运算
     *
     * @param v1 被乘数
     * @param v2 乘数
     * @return 两个参数的积
     */
    public static double mul(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.multiply(b2).doubleValue();
    }


    /**
     * 提供精确的乘法运算
     *
     * @param v1 被乘数
     * @param v2 乘数
     * @return 两个参数的积
     */
    public static BigDecimal mul(String v1, String v2) {
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.multiply(b2);
    }


    /**
     * 提供精确的乘法运算
     *
     * @param v1    被乘数
     * @param v2    乘数
     * @param scale 保留scale 位小数
     * @return 两个参数的积
     */
    public static double mul(double v1, double v2, int scale) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return round(b1.multiply(b2).doubleValue(), scale);
    }


    /**
     * 提供精确的乘法运算
     *
     * @param v1    被乘数
     * @param v2    乘数
     * @param scale 保留scale 位小数
     * @return 两个参数的积
     */
    public static String mul(String v1, String v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.multiply(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
    }


    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到
     * 小数点以后10位,以后的数字四舍五入
     *
     * @param v1 被除数
     * @param v2 除数
     * @return 两个参数的商
     */


    public static double div(double v1, double v2) {
        return div(v1, v2, DEF_DIV_SCALE);
    }


    /**
     * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
     * 定精度,以后的数字四舍五入
     *
     * @param v1    被除数
     * @param v2    除数
     * @param scale 表示表示需要精确到小数点以后几位。
     * @return 两个参数的商
     */
    public static double div(double v1, double v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }


    /**
     * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
     * 定精度,以后的数字四舍五入
     *
     * @param v1    被除数
     * @param v2    除数
     * @param scale 表示需要精确到小数点以后几位
     * @return 两个参数的商
     */
    public static String div(String v1, String v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v1);
        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).toString();
    }


    /**
     * 提供精确的小数位四舍五入处理
     *
     * @param v     需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static double round(double v, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b = new BigDecimal(Double.toString(v));
        return b.setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }


    /**
     * 提供精确的小数位四舍五入处理
     *
     * @param v     需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static String round(String v, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b = new BigDecimal(v);
        return b.setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
    }


    /**
     * 取余数
     *
     * @param v1    被除数
     * @param v2    除数
     * @param scale 小数点后保留几位
     * @return 余数
     */
    public static String remainder(String v1, String v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.remainder(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
    }


    /**
     * 取余数  BigDecimal
     *
     * @param v1    被除数
     * @param v2    除数
     * @param scale 小数点后保留几位
     * @return 余数
     */
    public static BigDecimal remainder(BigDecimal v1, BigDecimal v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        return v1.remainder(v2).setScale(scale, BigDecimal.ROUND_HALF_UP);
    }


    /**
     * 比较大小
     *
     * @param v1 被比较数
     * @param v2 比较数
     * @return 如果v1 大于v2 则 返回true 否则false
     */
    public static boolean compare(String v1, String v2) {
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        int bj = b1.compareTo(b2);
        boolean res;
        if (bj > 0)
            res = true;
        else
            res = false;
        return res;
    }
}

List集合操作的轮子

使用已经共用的轮子可以大幅度帮忙减少代码的重复开发,并且提高开发效率,轮子基本没有BUG

1 java.util包下的Collections类

排序-Collections.sort , Collections.reverse

在工作中经常有对集合排序的需求。

看看使用 java.util包下的Collections工具是如何实现升序和降序的:

  List<Integer> list = new ArrayList<>();
  list.add(2);
  list.add(1);
  list.add(3);
  Collections.sort(list);//升序
  System.out.println(list);
  Collections.reverse(list);//降序
  System.out.println(list);

执行结果:

[1, 2, 3]
[3, 2, 1]

获取最大或最小值 -Collections.max ,Collections.min

有时候需要找出集合中的最大值或者最小值,这时可以使用Collections的max和min方法。例如:

List<Integer> list = new ArrayList<>();
list.add(2);
list.add(1);
list.add(3);
Integer max = Collections.max(list);//获取最大值
Integer min = Collections.min(list);//获取最小值
System.out.println(max);
System.out.println(min);

执行结果:

3
1

转换线程安全集合Collections.synchronizedxxx

我们都知道,java中的很多集合,比如:ArrayList、LinkedList、HashMap、HashSet等,都是线程不安全的。

换句话说,这些集合在多线程的环境中,添加数据会数据紊乱的问题

这时,可以用Collections的synchronizedxxx方法,将这些线程不安全的集合,直接转换成线程安全集合。例如:

  List<Integer> list = new ArrayList<>();
  list.add(2);
  list.add(1);
  list.add(3);


  List<Integer> integers = Collections.synchronizedList(list);//将ArrayList转换成线程安全集合
  System.out.println(integers);

它的底层会创建SynchronizedRandomAccessList或者SynchronizedList类,这两个类的很多方法都会用synchronized加锁。

返回空集合 -Collections.emptyList()

有时,我们在判空之后,需要返回空集合,就可以使用emptyList方法,例如:

private List<Integer> fun(List<Integer> list) {
    if (list == null || list.size() == 0) {
        return Collections.emptyList();
    }
    //业务处理
    return list;
}

随机打乱集合中元素的顺序- Collections.shuffle

public class Main {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        for (int i = 0; i < 10; i++)
            list.add(new Integer(i));
        System.out.println("打乱前:");
        System.out.println(list);
 
        for (int i = 1; i < 6; i++) {
            System.out.println("第" + i + "次打乱:");
            Collections.shuffle(list);
            System.out.println(list);
        }
    }
}

以上代码运行输出结果为:

打乱前:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
第1次打乱:
[2, 0, 5, 1, 4, 9, 7, 6, 3, 8]
第2次打乱:
[2, 6, 4, 8, 5, 7, 9, 1, 0, 3]
第3次打乱:
[6, 5, 1, 0, 3, 7, 2, 4, 9, 8]
第4次打乱:
[1, 3, 8, 4, 7, 2, 0, 6, 5, 9]
第5次打乱:
[3, 0, 7, 9, 5, 8, 4, 2, 1, 6]

2 java.util包下的Arrays类

初始化一个集合Arrays.asList()

List<Integer> list = Arrays.asList(1, 2, 3);

注意: Arrays.asList返回的List对象是Arrays的一个内部类无法实现集合修改

并没有实现集合修改,因此调用其add/addAll/remove/clear等方法是会报错的。Arrays.asList体现的是适配器模式,其后台数据仍是数组。

List<VideoOrder> videoOrders1 = Arrays.asList(
 new VideoOrder("20190242812", "springboot教程", 3)
  );


List<VideoOrder> videoOrders2 = Arrays.asList(
        new VideoOrder("2019024285312", "springboot教程", 3)
    );
 boolean is=  videoOrders1.addAll(videoOrders2);
  
//会报错Exception in thread "main" java.lang.UnsupportedOperationException

解决方法1:通过stream流

可以java8新特性的stream流来解决,可以把asList返回的List对象通过Stream流去转换真正的List对象,这样就可以直接add/addAll/remove/clear等方法了

List<VideoOrder> collectorderlist1 = videoOrders1.parallelStream().collect(Collectors.toList());
boolean b = collectorderlist1.addAll(videoOrders2);

解决方法2 :使用Lists.newArrayList或者直接New 集合

数组转成一个集合方式1 Arrays.asList()

  String[] namesArr = {"joshua317","joshua318","joshua319"};
 List<String> namesLst = Arrays.asList(namesArr);

该方法返回的List是长度是固定的(fixed),不是只读的。所以我们不能进行删除、添加操作,而可以使用set()方法进行修改元素操作。如果你对返回的List执行add()添加或者删除元素,会返回UnsupportedOperationException。

数组转成一个集合方式2 Arrays.stream()-推荐

String[] namesArr = {"joshua317","joshua318","joshua319"};
List<String> collect = Arrays.stream(namesArr).collect(Collectors.toList());
collect.add("haha");
System.out.println(collect);

可以java8新特性的stream流来解决,可以把asList返回的List对象通过Stream流去转换真正的List对象,这样就可以直接 add/addAll/remove/clear等方法了

3 apache的CollectionUtils工具类

Spring也有 CollectionUtils工具类spring的org.springframework.util包下的CollectionUtils工具类。 但是我们一般都是用apache的org.apache.commons.collections包下的CollectionUtils工具类

<dependency>
    <groupId>commons-collections</groupId>
    <artifactId>commons-collections</artifactId>
    <version>3.2.2</version>
</dependency>

集合判空 CollectionUtils.isNotEmpty , CollectionUtils.isEmpty

通过CollectionUtils工具类的isEmpty方法可以轻松判断集合是否为空,isNotEmpty方法判断集合不为空。

List<Integer> list = new ArrayList<>();
list.add(2);
list.add(1);
list.add(3);


if (CollectionUtils.isEmpty(list)) {
    System.out.println("集合为空");
}


if (CollectionUtils.isNotEmpty(list)) {
    System.out.println("集合不为空");
}

对两个集合进行操作--对两个集合取 交集,并集,补集,差集

List<Integer> list = new ArrayList<>();
list.add(2);
list.add(1);
list.add(3);


List<Integer> list2 = new ArrayList<>();
list2.add(2);
list2.add(4);


//获取并集
Collection<Integer> unionList = CollectionUtils.union(list, list2);
System.out.println(unionList);


//获取交集
Collection<Integer> intersectionList = CollectionUtils.intersection(list, list2);
System.out.println(intersectionList);


//获取交集的补集
Collection<Integer> disjunctionList = CollectionUtils.disjunction(list, list2);
System.out.println(disjunctionList);


//获取差集
Collection<Integer> subtractList = CollectionUtils.subtract(list, list2);
System.out.println(subtractList);

执行结果:

[1, 2, 3, 4]
[2]
[1, 3, 4]
[1, 3]

说句实话,对两个集合的操作,在实际工作中用得挺多的,特别是很多批量的场景中。以前我们需要写一堆代码,但没想到有现成的轮子。

4 com.google.common.collect 包下的Lists

引入相关依赖

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>21.0</version>
</dependency>

创建空集合-Lists.newArrayList

有时候,我们想创建一个空集合。这时可以用Lists的newArrayList方法,例如:

List<Integer> list = Lists.newArrayList();

快速初始化集合-Lists.newArrayList

有时候,我们想给一个集合中初始化一些元素。这时可以用Lists的newArrayList方法,例如:

List<Integer> list = Lists.newArrayList(1, 2, 3);

这个方法可以弥补Arrays.asList方法初始化后的集合无法修改的缺点

执行结果:

[1, 2, 3]

求两个集合的笛卡尔积-Lists.cartesianProduct

如果你想将两个集合做笛卡尔积,Lists的cartesianProduct方法可以帮你实现:

List<Integer> list1 = Lists.newArrayList(1, 2, 3);
List<Integer> list2 = Lists.newArrayList(4,5);
List<List<Integer>> productList = Lists.cartesianProduct(list1,list2);
System.out.println(productList);

执行结果:

[[1, 4], [1, 5], [2, 4], [2, 5], [3, 4], [3, 5]]

Lists.partition-将一个大集合分成若干个小集合

将list集合按指定长度进行切分,返回新的List<List<??>>集合

引入相关依赖

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>21.0</version>
</dependency>

List<Integer> list = Lists.newArrayList(1, 2, 3, 4, 5);


List<List<Integer>> partitionList = Lists.partition(list, 2);


System.out.println(partitionList);

执行结果:

[[1, 2], [3, 4], [5]]

这个例子中,list有5条数据,我将list集合按大小为2,切分成了3个小集合。

使用场景:

1 这个方法在分批操作中非常有用,如分批查询,分批调用

比如有个需求:现在有5000个id,需要调用批量用户查询接口,查出用户数据。但如果你直接查5000个用户,单次接口响应时间可能会非常慢。如果改成分批处理,每次只查500个用户,异步调用10次接口,就不会有单次接口响应慢的问题。

流处理-Lists.transform

如果我们想把某个集合转换成另外一个接口,可以使用Lists的transform方法。例如:

List<String> list = Lists.newArrayList("a","b","c");
List<String> transformList = Lists.transform(list, x -> x.toUpperCase());
System.out.println(transformList);

将小写字母转换成了大写字母。

颠倒顺序-Lists.reverse (将集合倒过来 )

原来是第一个的元素,现在变成最后一个 注意:这里只是颠倒顺序,不是倒叙排序

Lists的有颠倒顺序的方法reverse。例如:

List<Integer> list = Lists.newArrayList(3, 1, 2);
List<Integer> reverseList = Lists.reverse(list);
System.out.println(reverseList);

执行结果:

[2, 1, 3]

list的原始顺序是312,使用reverse方法颠倒顺序之后,变成了213。

5 集合初始化的所有方式

Java 中初始化 List 集合的 6 种方式! - Java技术栈 - 博客园 (cnblogs.com)

1 直接New对象

List<String> languages = new ArrayList<>();

2,Arrays 工具类

List<String> jdks = asList("JDK6", "JDK8", "JDK10");

3,Collections 工具类

List<String> cat = Collections.singletonList("cat");

4,Lists工具类

  Lists.newArrayList()
  Lists.newArrayListWithCapacity(500)

集合类型数据开发的注意事项

1 Arrays.asList返回的List对象是Arrays的一个内部类

并没有实现集合修改,因此调用其add/addAll/remove/clear等方法是会报错的。Arrays.asList体现的是适配器模式,其后台数据仍是数组。

List<VideoOrder> videoOrders1 = Arrays.asList(
 new VideoOrder("20190242812", "springboot教程", 3)
  );


List<VideoOrder> videoOrders2 = Arrays.asList(
        new VideoOrder("2019024285312", "springboot教程", 3)
    );
 boolean is=  videoOrders1.addAll(videoOrders2);
  
//会报错Exception in thread "main" java.lang.UnsupportedOperationException

解决方法:通过stream流

可以java8新特性的stream流来解决,可以把asList返回的List对象通过Stream流去转换真正的List对象,这样就可以直接add/addAll/remove/clear等方法了

List<VideoOrder> collectorderlist1 = videoOrders1.parallelStream().collect(Collectors.toList());
boolean b = collectorderlist1.addAll(videoOrders2);

2 List的contains方法在判断一个对象是否属于List时,默认比较的是内存地址(只是判定是否是同一个对象)。这基本不符合业务需求

List<VideoOrder> videoOrders1 = Arrays.asList(
 new VideoOrder("20190242812", "springboot教程", 3)
  );


List<VideoOrder> videoOrders2 = Arrays.asList(
        new VideoOrder("20190242812", "springboot教程", 3)
    );
    
List<VideoOrder> collect =
  videoOrders1.stream().filter((obj) -> videoOrders2.contains(obj)).collect(Collectors.toList());
//返回值是一个[],因为这个两个集合中的对象,虽然值相同,但是依然不是同一个对象

解决方法:通过重写equals和hashCode方法去解决

一般业务场景决定,判断两个对象是否相同,比较它们的全部值,或者部分值就可以了,无需去比较内存地址(判断是否是同一个对象)

public int hashCode() {
    //只要名称的HashCode相同即可
    return title.hashCode();
}


@Override
public boolean equals(Object obj) {
    if(obj instanceof VideoOrder)
    {
        VideoOrder videoOrder= (VideoOrder) obj;
        //只要名称相同,我们就认为这个两个VideoOrder对象相同
        if(videoOrder.getTitle().equals(this.title))
        {
            return  true;
        }
        return false;
    }
    return super.equals(obj);
}

3 Stream流的distinct操作在判断对象是否重复时(重复就去重),默认比较的是内存地址(只是判定是否是同一个对象)。这基本不符合业务需求

解决方法:通过重写equals和hashCode方法去解决

一般业务场景决定,判断两个对象是否重复,比较它们的全部值,或者部分值就可以了,无需去比较内存地址(判断是否是同一个对象)

public int hashCode() {
    //只要名称的HashCode相同即可
    return title.hashCode();
}


@Override
public boolean equals(Object obj) {
    if(obj instanceof VideoOrder)
    {
        VideoOrder videoOrder= (VideoOrder) obj;
        //只要名称相同,我们就认为这个两个VideoOrder对象相同
        if(videoOrder.getTitle().equals(this.title))
        {
            return  true;
        }
        return false;
    }
    return super.equals(obj);
}

对象工具Objects 与ObjectUtils

Objects

对象判空-isNull ,nonNull

在java中万事万物皆对象,对象的判空可以说无处不在。Objects的isNull方法判断对象是否为空,而nonNull方法判断对象是否不为空。例如:

Integer integer = new Integer(1);


if (Objects.isNull(integer)) {
    System.out.println("对象为空");
}


if (Objects.nonNull(integer)) {
    System.out.println("对象不为空");
}

对象为空抛异常-requireNonNull

如果我们想在对象为空时,抛出空指针异常,可以使用Objects的requireNonNull方法。例如:

Integer integer1 = new Integer(128);


Objects.requireNonNull(integer1);
Objects.requireNonNull(integer1, "参数不能为空");
Objects.requireNonNull(integer1, () -> "参数不能为空");

判断两个对象是否相等-equals

我们经常需要判断两个对象是否相等,Objects给我们提供了equals方法,能非常方便的实现:

注意字符串判空用org.apache.commons.lang3包下StringUtils

Integer integer1 = new Integer(1);
Integer integer2 = new Integer(1);


System.out.println(Objects.equals(integer1, integer2));

执行结果:

true
1

但使用这个方法有坑,(因为它比较的是内存地址)比如例子改成:

Integer integer1 = new Integer(1);
Long integer2 = new Long(1);


System.out.println(Objects.equals(integer1, integer2));

执行结果:

false

获取对象的hashCode--hashCode

如果你想获取某个对象的hashCode,可以使用Objects的hashCode方法。例如:

String str = new String("abc");
System.out.println(Objects.hashCode(str));

执行结果:

96354

ObjectUtils--一般用它

我们最好使用apache包下的ObjectUtils

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.10</version>
</dependency>

对象判空- isNotEmpty,isEmpty

判断两个对象是否相等-equals,notEqual

也是默认比较的内存地址

故以下结果为false

Integer integer1 = new Integer(1);
Long integer2 = new Long(1);


System.out.println(Objects.equals(integer1, integer2));

执行结果:

false

注意字符串判空用org.apache.commons.lang3包下StringUtils

字符串工具

1 org.apache.commons.lang3包下StringUtils

字符串(String)在我们的日常工作中,用得非常非常非常多。

在我们的代码中经常需要对字符串判空,截取字符串、转换大小写、分隔字符串、比较字符串、去掉多余空格、拼接字符串、使用正则表达式等等。

如果只用String类提供的那些方法,我们需要手写大量的额外代码,不然容易出现各种异常。

现在有个好消息是:org.apache.commons.lang3包下的StringUtils工具类,给我们提供了非常丰富的选择。

Spring也有StringUtils,但是我们一般只使用 org.apache.commons.lang3包下的 StringUtils

dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.10</version>
</dependency>

字符串判空-isEmpty、isNotEmpty、isBlank和isNotBlank

其实空字符串,不只是null一种,还有"“,” ","null"等等,多种情况。

优先推荐使用isBlank和isNotBlank方法,因为它会把" "也考虑进去。

StringUtils给我们提供了多个判空的静态方法,例如:

String str1 = null;
String str2 = "";
String str3 = " ";
String str4 = "abc";
System.out.println(StringUtils.isEmpty(str1));
System.out.println(StringUtils.isEmpty(str2));
System.out.println(StringUtils.isEmpty(str3));
System.out.println(StringUtils.isEmpty(str4));
System.out.println("=====");
System.out.println(StringUtils.isNotEmpty(str1));
System.out.println(StringUtils.isNotEmpty(str2));
System.out.println(StringUtils.isNotEmpty(str3));
System.out.println(StringUtils.isNotEmpty(str4));
System.out.println("=====");
System.out.println(StringUtils.isBlank(str1));
System.out.println(StringUtils.isBlank(str2));
System.out.println(StringUtils.isBlank(str3));
System.out.println(StringUtils.isBlank(str4));
System.out.println("=====");
System.out.println(StringUtils.isNotBlank(str1));
System.out.println(StringUtils.isNotBlank(str2));
System.out.println(StringUtils.isNotBlank(str3));
System.out.println(StringUtils.isNotBlank(str4));

执行结果:

true
true
false
false
=====
false
false
true
true
=====
true
true
true
false
=====
false
false
false
true

示例中的:isEmpty、isNotEmpty、isBlank和isNotBlank,这4个判空方法你们可以根据实际情况使用。

分隔字符串--StringUtils.split

分隔字符串是常见需求,如果直接使用String类的split方法,就可能会出现空指针异常。

String str1 = null;
System.out.println(StringUtils.split(str1,","));
System.out.println(str1.split(","));

执行结果:

null
Exception in thread "main" java.lang.NullPointerException
 at com.sue.jump.service.test1.UtilTest.main(UtilTest.java:21)

使用StringUtils的split方法会返回null,而使用String的split方法会报指针异常。

判断一个字符串是否是纯数字-StringUtils.isNumeric

给定一个字符串,判断它是否为纯数字(整数),可以使用isNumeric方法。例如:

注意有小数的情况--有小数点会认为不是纯数字

String str1 = "123";
String str2 = "123q";
String str3 = "0.33";
System.out.println(StringUtils.isNumeric(str1));
System.out.println(StringUtils.isNumeric(str2));
System.out.println(StringUtils.isNumeric(str3));

执行结果:

true
false
false

字符串的拼接AND将集合拼接成字符串- StringUtils.join

字符串的拼接

String join = StringUtils.join(1,2,"ad");
System.out.println(join);
//打印结果12ad

将集合拼接成字符串

有时候,我们需要将某个集合的内容,拼接成一个字符串,并且每个集合元素之间用指定分隔符,分开,然后输出,

这时可以使用join方法。例如:

List<String> list = Lists.newArrayList("a", "b", "c");
List<Integer> list2 = Lists.newArrayList(1, 2, 3);
System.out.println(StringUtils.join(list, ","));
System.out.println(StringUtils.join(list2, " "));

执行结果:

a,b,c
1 2 3

判断字符串是否包含某个元素-StringUtils.contains

1. StringUtils中判断是否包含的方法主要有:

contains(CharSequence seq, int searchChar)


contains(CharSequence seq, CharSequence searchSeq)


containsIgnoreCase(CharSequence str, CharSequence searchStr)


containsAny(CharSequence cs, char... searchChars)


containsAny(CharSequence cs, CharSequence searchChars)


containsOnly(CharSequence cs,char… valid)


containsOnly(CharSequence cs, String validChars)


containsNone(CharSequence cs,char… searchChars)


containsNone(CharSequence cs, String invalidChars)


startsWith(CharSequence str,CharSequence prefix)


startsWithIgnoreCase(CharSequence str,CharSequence prefix)


startsWithAny(CharSequence string,CharSequence… searchStrings)

(1)判断字符串中是否包含指定的字符或字符序列:

a)区分大小写:

StringUtils.contains(null, 'a'); // false


StringUtils.contains("china", 'A'); // false


StringUtils.contains("", 'a'); // false


StringUtils.contains("china", 'a');// true


StringUtils.contains("china", 'z');//false


StringUtils.contains(null, "a"); // false


StringUtils.contains("china", null); // false


StringUtils.contains("", ""); // true


StringUtils.contains("abc", "");// true


StringUtils.contains("china", "na");// true

b)不区分大小写:

StringUtils.containsIgnoreCase("china", 'a');// true


StringUtils.containsIgnoreCase("china", 'A');// true


StringUtils.containsIgnoreCase("china", 'Z');//false


StringUtils.containsIgnoreCase(null, "A"); // false


StringUtils.containsIgnoreCase("china", null); // false


StringUtils.containsIgnoreCase("", ""); // true


StringUtils.containsIgnoreCase("abc", "");// true         


StringUtils.containsIgnoreCase("china", "na");// true


StringUtils.containsIgnoreCase("china", "Na");// true

(2)判断字符串中是否包含指定字符集合中或指定字符串中任一字符,区分大小写:

StringUtils.containsAny(null, 'a', 'b');// false


StringUtils.containsAny("", 'a', 'b');// false


StringUtils.containsAny("abc", 'a', 'z');// true


StringUtils.containsAny("abc", 'x', 'y');// false


StringUtils.containsAny("abc", 'A', 'z');// false


StringUtils.containsAny(null, "a");// false


StringUtils.containsAny("", "a");// false


StringUtils.containsAny("abc", "ab");// true


StringUtils.containsAny("abc", "ax");// true


StringUtils.containsAny("abc", "xy");// false


StringUtils.containsAny("abc", "Ax");// false

(3)判断字符串中是否不包含指定的字符或指定的字符串中的字符,区分大小写:

StringUtils.containsNone(null, 'a'); // true


StringUtils.containsNone("", 'a'); // true 注意这里,空串总是返回true


StringUtils.containsNone("china", ' '); // true 注意包含空白符为true


StringUtils.containsNone("china", '\t'); // true


StringUtils.containsNone("china", '\r'); // true


StringUtils.containsNone("china", 'x', 'y', 'z'); // true


StringUtils.containsNone("china", 'c', 'y', 'z'); // false


StringUtils.containsNone("china", 'C', 'y', 'z'); // true


StringUtils.containsNone(null, "a"); // true


StringUtils.containsNone("", "a"); // true


StringUtils.containsNone("china", ""); // true


StringUtils.containsNone("china", "xyz"); // true


StringUtils.containsNone("china", "cyz"); // false


StringUtils.containsNone("china", "Cyz"); // true

(4)判断字符串中的字符是否都是出自所指定的字符数组或字符串,区分大小写:

StringUtils.containsOnly(null, 'a');// false


StringUtils.containsOnly("", "a");// true


StringUtils.containsOnly("ab", ' ');// false


StringUtils.containsOnly("abab", 'a', 'b', 'c');// true


StringUtils.containsOnly("abcd", 'a', 'b', 'c');// false


StringUtils.containsOnly("Abab", 'a', 'b', 'c');// false


StringUtils.containsOnly(null, "a");// false


StringUtils.containsOnly("", "a"); // true


StringUtils.containsOnly("abab", "abc));// true


StringUtils.containsOnly("abcd", "abc"); // false


StringUtils.containsOnly("Abab", "abc");// false

(5)判断字符串是否以指定的字符序列开头:

a)区分大小写:

StringUtils.startsWith(null, null); // true


StringUtils.startsWith(null, "abc"); // false


StringUtils.startsWith("abcdef", null); // false


StringUtils.startsWith("abcdef", "abc"); // true


StringUtils.startsWith("ABCDEF", "abc"); // false

b)不区分大小写:

StringUtils.startsWithIgnoreCase(null, null);// true


StringUtils.startsWithIgnoreCase(null, "abc");// false


StringUtils.startsWithIgnoreCase("abcdef", null);// false


StringUtils.startsWithIgnoreCase("abcdef", "abc");// true


StringUtils.startsWithIgnoreCase("ABCDEF", "abc");// true

(6)判断字符串是否以指定的字符序列数组中任意一个开头,区分大小写:

StringUtils.startsWithAny(null, null);// false


StringUtils.startsWithAny(null, new String[] { "abc" });// false


StringUtils.startsWithAny("abcxyz", null);// false


StringUtils.startsWithAny("abcxyz", new String[] { "" });// true


StringUtils.startsWithAny("abcxyz", new String[] { "abc" });// true


StringUtils.startsWithAny("abcxyz", new String[] { null, "xyz", "abc" });// true


StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX");// false


StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc");// false

字符串的大小写问题

StringUtils中涉及大小写转换以及判断字符串大小写的方法如下:

StringUtils.capitalize(String str)
StringUtils.uncapitalize(String str)
StringUtils.upperCase(String str)
StringUtils.upperCase(String str,Locale locale)
StringUtils.lowerCase(String str)
StringUtils.lowerCase(String str,Locale locale)
StringUtils.swapCase(String str)
StringUtils.isAllUpperCase(CharSequence cs)
StringUtils.isAllLowerCase(CharSequence cs)

字符串首字母大小写转换 capitalize ,uncapitalize

    StringUtils.capitalize(null)); // null (注意此处不会报异常)
    StringUtils.capitalize("china")); // China (首字母转大写)
    StringUtils.uncapitalize(null)); // null  
    StringUtils.uncapitalize("CHINA")); // cHINA (首字母转小写)

字符串整体大小写转换 upperCase ,lowerCase

    StringUtils.upperCase(null)); // null
    StringUtils.upperCase("china")); // CHINA (全部转为大写)
    StringUtils.upperCase("china", Locale.ENGLISH)); // CHINA (按照指定规则转换为大写)
    StringUtils.lowerCase(null)); // null
    StringUtils.lowerCase("CHINA")); // china (全部转换为小写)
    StringUtils.lowerCase("CHINA", Locale.ENGLISH)); // china (按照指定转换规则转换为小写)

字符串大小写互换 swapCase

    StringUtils.swapCase(null)); // null
    StringUtils.swapCase("chINA")); // CHina

判断字符串是否全部是大写或小写(空或空字符串均为false)

    StringUtils.isAllUpperCase(null)); // false


    StringUtils.isAllUpperCase("")); // false


    StringUtils.isAllUpperCase(" ")); // false


    StringUtils.isAllUpperCase("CHINA")); // true


    StringUtils.isAllLowerCase(null)); // false


    StringUtils.isAllLowerCase("")); // false


    StringUtils.isAllLowerCase(" ")); // false


    StringUtils.isAllLowerCase("china")); // true

字符串的去空格-deleteWhitespace,trim

 StringUtils 中封装了部分方法来去除字符串中的空白符:

trim(String str)
trimToEmpty(String str)
trimToNull(String str)
strip(String str)
stripToEmpty(String str)
stripToNull(String str)
deleteWhitespace(String str)

1):去除字符串首尾的控制符(char <= 32)

a)trim(String str):如果被去除的字符串的为null或"",则返回null和"":

StringUtils.trim(null); // null
StringUtils.trim(""); // ""
StringUtils.trim("     ");// ""
StringUtils.trim("    abc    "); // abc
StringUtils.trim(" a b c "); // "a b c" 注意此处字符串内部的控制符是不去除的

b)trimToEmpty(String str):如果被去除的字符串的为null或"",则都返回"":

StringUtils.trimToEmpty(null); // "" 此处返回的是""
StringUtils.trimToEmpty(""); // ""
StringUtils.trimToEmpty("     ");// ""
StringUtils.trimToEmpty("    abc    "); // abc
StringUtils.trimToEmpty(" a b c "); // a b c

c)trimToNull(String str):如果被去除的字符串的为null或"",则都返回null:

StringUtils.trimToNull(null); // null
StringUtils.trimToNull(""); // null
StringUtils.trimToNull("     ");// null
StringUtils.trimToNull(" \t\r\nabc    "); // abc
StringUtils.trimToNull(" a b c "); // "a b c" 

2)去除字符串首尾的空白符(空白符主要包括’ ‘,’\t’,’\r’,’\n’等等,具体可以参考Java API中Character类中isWhiteSpace()方法中的描述):

a)trim(String str):如果被去除的字符串的为null或"",则返回null和"":

StringUtils.strip(""); // ""
StringUtils.strip("     ");// ""
StringUtils.strip(null); // null
StringUtils.strip(" \t\r\n abc    "); // abc
StringUtils.strip(" a b c "); // a b c

b)trimToEmpty(String str):如果被去除的字符串的为null或"",则都返回"":

StringUtils.stripToEmpty(null); //""
StringUtils.stripToEmpty(""); // "" StringUtils.stripToEmpty(" ");// "" StringUtils.stripToEmpty(" \t\r\n abc "); // abc StringUtils.stripToEmpty(" a b c "); // "a b c"

c)trimToNull(String str):如果被去除的字符串的为null或"",则都返回null:

StringUtils.stripToNull(null); // null
StringUtils.stripToNull(""); // null
StringUtils.stripToNull("     ");// null
StringUtils.stripToNull(" \t\r\n abc    "); // abc
StringUtils.stripToNull(" a b c "); // "a b c"

3)去除字符串中所有的空白符:(一般使用这种)

StringUtils.deleteWhitespace(null); // null
StringUtils.deleteWhitespace(""); // ""
StringUtils.deleteWhitespace("abc"); // "abc"
StringUtils.deleteWhitespace("   ab  c  "); // "abc"

字符值的移除 remove ,removeXX

从字符串中移除匹配的字符或字符序列,如果要移除的字符或字符序列在字符串中不存在,即无匹配,则不进行移除

    1)StringUtils.remove(String str, char remove)


    2)StringUtils.remove(String str, String remove)


    3)StringUtils.removeStart(String str, String remove)


    4)StringUtils.removeStartIgnoreCase(String str, String remove)


    5)StringUtils.removeEnd(String str, String remove)


    6)StringUtils.removeEndIgnoreCase(String str, String remove)


    7)StringUtils.deleteWhitespace(String str)

(1)移除单个字符

    StringUtils.remove(null, 'a')); // null (注意此处及下一行为null)


    StringUtils.remove('china', null) // china 


    StringUtils.remove("china", 'i')); // chna


    StringUtils.remove("china", 'b')); // china (如果要移除的字符不存在,则返回原字符串)

(2)移除指定字符序列

    StringUtils.remove("china", "in")); // cha


    StringUtils.remove("china", "nin")); // china

(3)移除开头匹配的字符序列

    StringUtils.removeStart("china", "ch")); // ina


    StringUtils.removeStartIgnoreCase("china", "CHI")); // na (忽略大小写)

(4)移除结尾匹配的字符序列

    StringUtils.removeEnd("china", "na")); // chi


    StringUtils.removeEndIgnoreCase("china", "NA")); // chi (忽略大小写)

(5)移除空白字符

    StringUtils.deleteWhitespace(null)); //null


    StringUtils.deleteWhitespace(" c h  i\tn\ra")); 

字符串值的替换-replace

StringUtils中常用的替换方法有如下几种

需要注意的是,若被替换的字符串为null,或者被替换的字符或字符序列为null,又或者替换的字符或字符序列为null,那么此次替换都会被忽略,返回原字符串

    1)replace(String text, String searchString, String replacement)


    2)replace(String text, String searchString, String replacement, int max)


    3)replaceChars(String str, char searchChar, char replaceChar)


    4)replaceChars(String str, String searchChars, String replaceChars)


    5)replaceOnce(String text, String searchString, String replacement)


    6)overlay(String str,String overlay,int start,int end)


    7)replaceEach(String text, String[] searchList, String[] replacementList)


    8)replaceEachRepeatedly(String text, String[] searchList, String[]replacementList)

(1)替换单个字符或指定的字符序列

(a)replace方法

replace方法可以替换单个字符序列(一般只用到这个)

StringUtils.replace("china", null, "z")); // china (此处被替换字符序列为null,因此替换会被忽略,返回原字符串)
StringUtils.replace("china", "c", null)); // china (此处替换字符序列为null,因此替换也被忽略,返回原字符串)
 StringUtils.replace("china", "a", "ese")); // chinese
 StringUtils.replace("china", "a", "")); // chin

replace方法还可以指定最大替换的个数

        StringUtils.replace("aabaaa", "a", "z", 0)); // aabaaa (0表示替换的个数为0,也就是不替换)


        StringUtils.replace("aabaaa", "a", "z", 1)); // zabaaa (1表示最多替换1个)


        StringUtils.replace("aabaaa", "a", "z", 2)); // zzbaaa (2表示最多替换2个)


        StringUtils.replace("aabaaa", "a", "z", 3)); // zzbzaa (3表示最多替换3个)


        StringUtils.replace("aabaaa", "a", "z", -1)); // zzbzaa (-1表示全部替换)

(b)replaceChars方法

replaceChars方法可以替换单个字符或者单个字符序列

        StringUtils.replaceChars("china", 'a', 'z')); // chinz


        StringUtils.replaceChars("china", "a", "z")); // chinz

(c)replaceOnce方法

replaceOnce方法只会替换一次,也就是只会替换第一个要替换的字符序列,后面即使有匹配的字符序列也不会被替换

        StringUtils.replaceOnce("abaa", "a", "z")); // zbaa

(d)overlay方法

overlay(String str,String overlay,int start,int end)方法可以在指定位置进行字符序列替换,从start索引处开始(包含)到end-1索引处为止进行替换

         StringUtils.overlay("abcdef", "zzzz", 2, 4)); // abzzzzef

这里有一些特殊情况:

1)起始索引start小于结束索引end,这时会将end作为起始索引,start作为结束索引

         StringUtils.overlay("abcdef", "zzzz", 4, 2)); // abzzzzef


         StringUtils.overlay("abcdef", "zzzz", 4, 3)); // abczzzzef


         StringUtils.overlay("abcdef", "zzzz", 4, 4)); // abcdzzzzef


         StringUtils.overlay("abcdef", "zzzz", 4, 5)); // abcdzzzzf

2)起始索引start为负数,这时start会被当作0处理

         StringUtils.overlay("abcdef", "zzzz", -1, 2)); // abcdzz


         StringUtils.overlay("abcdef", "zzzz", -2, -3)); // zzzzabcdef

3)结束索引end大于原始字符串的长度,这时end会被当作原始字符串长度处理

         StringUtils.overlay("abcdef", "zzzz", 8, 10)); // abcdefzzzz

(2)同时替换多个字符序列

(a)replaceEach方法

replaceEach(String text, String[] searchList, String[] replacementList)方法可以同时替换多个字符序列,但被替换和替换的字符序列的个数应该对应,否则会报IllegalArgumentException

         StringUtils.replaceEach("china", new String[] { "ch", "a" }, new String[] { "x", "z" })); // xhinz (将ch和a分别替换为x和z)


         StringUtils.replaceEach("china", null, new String[] { "x", "z" })); // china (存在null,不进行替换)


         StringUtils.replaceEach("china", new String[] { "ch", "a" }, new String[] { "x", "z", "y" })); // IllegalArgumentException (被替换和替换的个数不对应)

(b)replaceEachRepeatedly方法

replaceEachRepeatedly(String text, String[] searchList, String[] replacementList)方法可以循环进行替换,具体见下面的例子:

           StringUtils.replaceEachRepeatedly("china", new String[] { "c", "x" }, new String[] { "x", "z" })); // zhina (c被替换为x,x又被替换为z)

但如果替换是一个死循环,则会报IllegalStateException:

           StringUtils.replaceEachRepeatedly("china", new String[] { "c", "x" }, new String[] { "x", "c" })); // IllegalStateException (c被替换为x,x又被替换为c)

字符串值的反转-reverse

StringUtils中有关反转的方法如下:

    1)reverse(String str)


    2)reverseDelimited(String str, char separatorChar)

(1)简单反转

reverse(String str)方法

    StringUtils.reverse("china")); // anihc

(2)根据指定分隔符进行反转,分隔符之间的字符不进行反转

    StringUtils.reverseDelimited("china", ',')); // china


    StringUtils.reverseDelimited("cxhinxa", 'x')); // axhinxz


    StringUtils.reverseDelimited("c.hin.a", '.')); // a.hin.c


    StringUtils.reverseDelimited("c.hina", '.')); // hina.c

2 java.util包下的StringJoiner

介绍与使用

StringJoiner是Java8新出的一个类,用于拼接由分隔符分隔的字符序列,并可选择性地从提供的前缀开始和以提供的后缀结尾。省的我们开发人员再次通过StringBuffer或者StingBuilder拼接。

StringJoiner sj = new StringJoiner(":", "[", "]");
sj.add("George").add("Sally").add("Fred");
String desiredString = sj.toString();
//代码输出为[George:Sally:Fred]


StringJoiner stringJoiner = new StringJoiner("","","");
StringJoiner d1 = stringJoiner.add("2").add("4").add("d");
System.out.println(d1.toString());
//24d




String join = StringUtils.join(1,2,"ad");
System.out.println(join);
//打印结果12ad

可以看到相比StringUtils.join,使用StringJoiner不仅仅可以实现字符串的拼接功能,还可以在拼接的同时指定起始符和末尾符,此外还可以指定每个拼接元素之间的分割符。

但是StringUtils.join不仅可以直接拼接字符串,还可以直接拼接其他类型,但是StringJoiner只能拼接字符串类型

StringJoiner 的源码

这个类的源码很简单,很容易就可以看明白。

package java.util;


public final class StringJoiner {
    private final String prefix;//前缀
    private final String delimiter;//间隔符(分隔符)
    private final String suffix;//后缀
    private StringBuilder value;//值


    private String emptyValue;//空值


    public StringJoiner(CharSequence delimiter) {
        this(delimiter, "", "");//默认前缀和后缀为"",重载调用
    }


    public StringJoiner(CharSequence delimiter,
                        CharSequence prefix,
                        CharSequence suffix) {
        //间隔符,前缀和后缀判断是否为null,null将抛出异常
        Objects.requireNonNull(prefix, "The prefix must not be null");
        Objects.requireNonNull(delimiter, "The delimiter must not be null");
        Objects.requireNonNull(suffix, "The suffix must not be null"); 
        // 成员变量赋值
        this.prefix = prefix.toString();
        this.delimiter = delimiter.toString();
        this.suffix = suffix.toString();
        this.emptyValue = this.prefix + this.suffix;//空值被设置为只有前后缀
    }
	//设置空值,检查是否为null
    public StringJoiner setEmptyValue(CharSequence emptyValue) {
        this.emptyValue = Objects.requireNonNull(emptyValue,
            "The empty value must not be null").toString();
        return this;
    }


    @Override
    public String toString() {
        if (value == null) {
            return emptyValue;//没有值将返回空值或者后续设置的空值
        } else {
            if (suffix.equals("")) {
                return value.toString();//后缀为""直接返回字符串,不用添加
            } else {
	            //后缀不为"",添加后缀,然后直接返回字符串,修改长度
                int initialLength = value.length();
                String result = value.append(suffix).toString();
                // reset value to pre-append initialLength
                value.setLength(initialLength);
                return result;
            }
        }
    }
    初始化,先添加前缀,有了之后每次先添加间隔符,StringBuilder后续append字符串
    public StringJoiner add(CharSequence newElement) {
        prepareBuilder().append(newElement);
        return this;
    }
	//合并StringJoiner,注意后面StringJoiner 的前缀就不要了,后面的appen进来
    public StringJoiner merge(StringJoiner other) {
        Objects.requireNonNull(other);
        if (other.value != null) {
            final int length = other.value.length();
            // lock the length so that we can seize the data to be appended
            // before initiate copying to avoid interference, especially when
            // merge 'this'
            StringBuilder builder = prepareBuilder();
            builder.append(other.value, other.prefix.length(), length);
        }
        return this;
    }
	//初始化,先添加前缀,有了之后每次先添加间隔符
    private StringBuilder prepareBuilder() {
        if (value != null) {
            value.append(delimiter);
        } else {
            value = new StringBuilder().append(prefix);
        }
        return value;
    }


    public int length() {
        // Remember that we never actually append the suffix unless we return
        // the full (present) value or some sub-string or length of it, so that
        // we can add on more if we need to.
        //不忘添加后缀的长度
        return (value != null ? value.length() + suffix.length() :
                emptyValue.length());
    }
}

3 字符串的格式化-String.format()

在 Java 中格式化字符串最常用的方法就是 String.format(),如果有一个 Java 版本的 printf,它会像下面这样:

String output = String.format("%s = %d", "joe", 35);

对于控制台中的格式化输出,可以使用 System.out 或 System.err 中的 printf() 或者 format()方法。

System.out.printf("My name is: %s%n", "joe");

格式说明符

以下是所有支持的转换说明符的快速参考。

说明符

适用于

输出

%a

浮点数 (除了BigDecimal)

浮点数的十六进制输出

%b

任何类型

如果为非空则为“true”,为空则为“false”

%c

字符

Unicode字符

%d

证书(包括byte, short, int, long, bigint)

十进制整数

%e

浮点数

科学计数的十进制数

%f

浮点数

十进制数

%g

浮点数

十进制数,根据值和精度可能以科学计数法显示

%h

任何类型

通过hashCode()方法输出的16进制数

%n

平台相关的换行符

%o

整数(包括byte, short, int, long, bigint)

八进制数

%s

任何类型

字符串

%t

日期/时间 (包含long, Calendar, Date 和TemporalAccessor)

%t是日期/时间转换的前缀。后面还需要跟其他的标识,请参考下面的日期/时间转换。

%x

整数(包含byte, short, int, long, bigint)

十六进制字符串

MapUtils

apache的MapUtils工具类

Spring也有 CollectionUtils工具类spring的org.springframework.util包下的MapUtils工具类。 但是我们一般都是用apache的org.apache.commons.collections包下的MapUtils工具类

<dependency>
    <groupId>commons-collections</groupId>
    <artifactId>commons-collections</artifactId>
    <version>3.2.2</version>
</dependency>

Map的判空操作-MapUtils.isEmpty ,MapUtils.isNotEmpty

判断Map对象是否为空(null),或者Map对象中的元素数量是否为空

boolean empty = MapUtils.isEmpty(map);
boolean notEmpty = MapUtils.isNotEmpty(map);

com.google.common.collect 包下的Maps

引入相关依赖

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>21.0</version>
</dependency>

Map的初始化Maps.newHashMap, Maps.newConcurrentMap

ConcurrentMap<String, String> objectObjectConcurrentMap = Maps.newConcurrentMap();


HashMap<String, String> objectObjectHashMap = Maps.newHashMap();

HashMap的循环遍历(重要)

entrySet()-返回hashMap中的所有Entry(节点)(键值对-映射项)(用的最多)

UserDo userDo3 = new UserDo("xiaasda4", 12, "q323");
UserDo userDo4 = new UserDo("adad", 22, "ad1232");


HashMap<String, UserDo> map = new HashMap<>();
map.put("test1",userDo3);
map.put("test2",userDo4);


//获取当前当前Map中所有的键值对   Map.entrySet()
Set<Map.Entry<String, UserDo>> entries = map.entrySet();
//当前Map中所有的键值对(Map.Entry<String, UserDo>)
//都在这个Set<Map.Entry<String, String>>Set集合中,之后我们遍历Set集合即可
for (Map.Entry<String, UserDo> entry : entries) {
   //当前键值对的Key
   entry.getKey();
  //当前键值对的Value
   entry.getValue();
 
   System.out.println("Entry:"+entry+"   Key:"+entry.getKey()+"   Value:"+entry.getValue());
}
//打印结果
Entry:test2=UserDo(name=adad, age=22, email=ad1232)   Key:test2   Value:UserDo(name=adad, age=22, email=ad1232)
Entry:test1=UserDo(name=xiaasda4, age=12, email=q323)   Key:test1   Value:UserDo(name=xiaasda4, age=12, email=q323)

keySet()-返回HashMap中所有的Key

Set<String> set = map.keySet();
for (String key : set) {
    System.out.println("key:"+key);
}
//打印结果
key:test2
key:test1

forEach()--遍历每个Entry,可以对每个Entry的Key或者Value做操作(用的多)

//HashMap中的forEach的源码


@Override
public void forEach(BiConsumer<? super K, ? super V> action) {
    Node<K,V>[] tab;
    if (action == null)
        throw new NullPointerException();
    if (size > 0 && (tab = table) != null) {
        int mc = modCount;
        for (int i = 0; i < tab.length; ++i) {
            for (Node<K,V> e = tab[i]; e != null; e = e.next)
                action.accept(e.key, e.value);
        }
        if (modCount != mc)
            throw new ConcurrentModificationException();
    }
}

示例代码

// 创建一个 HashMap
HashMap<String, Integer> prices = new HashMap<>();
// 往 HashMap 中插入映射项
prices.put("Shoes", 200);
prices.put("Bag", 300);
prices.put("Pant", 150);
System.out.println("Normal Price: " + prices);
System.out.print("Discounted Price: ");
//通过 lambda 表达式使用 forEach()
prices.forEach((key, value) -> {
    // value 价格减少百分之 10
    value = value - value * 10/100;
    System.out.print(key + "=" + value + " ");
});
System.out.println("   --prices:"+prices);


//打印结果
Normal Price: {Pant=150, Bag=300, Shoes=200}
Discounted Price: Pant=135 Bag=270 Shoes=180    --prices:{Pant=150, Bag=300, Shoes=200}




// 创建一个 HashMap
HashMap<String, UserDo> testMap = new HashMap<>();
UserDo userDo5 = new UserDo("adad", 22, "ad1232");
UserDo userDo6 = new UserDo("adad", 22, "ad1232");
// 往 HashMap 中插入映射项
testMap.put("Shoes", userDo5);
testMap.put("Bag", userDo6);
System.out.println("testMap " + testMap);
//通过 lambda 表达式使用 forEach()
testMap.forEach((key, value) -> {
    value.setAge(value.getAge()*10);
    System.out.println(key + "=" + value + " ");
});
System.out.println("testMap:"+testMap);


//打印结果
testMap {test2=UserDo(name=adad, age=22, email=ad1232), test1=UserDo(name=adad, age=22, email=ad1232)}
test2=UserDo(name=adad, age=220, email=ad1232) 
test1=UserDo(name=adad, age=220, email=ad1232) 
testMap:{test2=UserDo(name=adad, age=220, email=ad1232), test1=UserDo(name=adad, age=220, email=ad1232)}

Assert断言

很多时候,我们需要在代码中做判断:如果不满足条件,则抛异常。

有没有统一的封装呢?

其实spring utils中给我们提供了Assert类,它表示断言。但是里面的异常机制往往和我们的自己系统的异常机制不匹配故我们可以自己定义一个Assert断言类,可以大量用来替代 以下语句

if(条件不满足){
 抛出异常;
}

我们来看一下spring utils中给我们提供了Assert类常用的功能

断言判断参数是否为空

断言参数是否空,如果不满足条件,则直接抛异常。

String str = null;


Assert.isNull(str, "str必须为空");


Assert.isNull(str, () -> "str必须为空");


Assert.notNull(str, "str不能为空");

如果不满足条件就会抛出IllegalArgumentException异常。

断言判断集合是否为空

断言集合是否空,如果不满足条件,则直接抛异常。

List<String> list = null;


Map<String, String> map = null;


Assert.notEmpty(list, "list不能为空");


Assert.notEmpty(list, () -> "list不能为空");


Assert.notEmpty(map, "map不能为空");

如果不满足条件就会抛出IllegalArgumentException异常。

断言判断条件是否成立

断言是否满足某个条件,如果不满足条件,则直接抛异常。

List<String> list = null;


Assert.isTrue(CollectionUtils.isNotEmpty(list), "list不能为空");


Assert.isTrue(CollectionUtils.isNotEmpty(list), () -> "list不能为空");

但是spring utils中给我们提供的Assert里面的异常机制往往和我们的自己系统的异常机制不匹配故我们可以自己定义一个Assert断言类

switch语句

用来替换一些if elseIf else 语句比较好

switch 语法

switch case 语句语法格式如下:

switch(expression){
    case value :
       //语句
       break; //可选
    case value :
       //语句
       break; //可选
    //你可以有任意数量的case语句
    default : //可选
       //语句
}

switch case 语句有如下规则:

  • 1 switch 语句中的变量类型可以是: byte、short、int 或者 char。从 Java SE 7 开始,switch 支持字符串 String 类型了,同时 case 标签必须为字符串常量或字面量。

  • 2 switch 语句可以拥有多个 case 语句。每个 case 后面跟一个要比较的值和冒号。

  • 3 case 语句中的值的数据类型必须与switch 语句变量的数据类型相同,而且只能是常量类型或者字面常量。

  • 4 当变量的值与 case 语句的值相等时,那么 case 语句之后的语句开始执行,直到 break 语句出现才会跳出 switch 语句。

  • 5 当遇到 break 语句时,switch 语句终止。程序跳转到 switch 语句后面的语句执行。case 语句不必须要包含 break 语句。如果没有 break 语句出现,程序会继续执行下一条 case 语句,直到出现 break 语句。(最好每个Case中都有break,不然可能会出问题)

  • 6 switch 语句可以包含一个 default 分支,该分支一般是 switch 语句的最后一个分支(可以在任何位置,但建议在最后一个)。default 在没有 case 语句的值和变量值相等的时候执行。default 分支不需要 break 语句(当然也可以写)
  • 7 当case 语句中包含了reture时,它不仅可以实现了break的效果,且还会终止当前方法

switch case 执行时,一定会先进行case匹配,匹配成功返回当前 case 的值,再根据是否有 break,判断是否继续输出,或是跳出判断。

switch的实例

正常的示例

public class Test {
   public static void main(String args[]){
      //char grade = args[0].charAt(0);
      char grade = 'C';
 
      switch(grade)
      {
         case 'A' :
            System.out.println("优秀"); 
            break;
         case 'B' :
         case 'C' :
            System.out.println("良好");
            break;
         case 'D' :
            System.out.println("及格");
            break;
         case 'F' :
            System.out.println("你需要再努力努力");
            break;
         default :
            System.out.println("未知等级");
      }
      System.out.println("你的等级是 " + grade);
   }
}

以上代码编译运行结果如下:

良好
你的等级是 C

如果 case 语句块中没有 break 语句时的几种情况示例

情况1:如果 case 语句块中没有 break 语句时,JVM 并不会顺序输出每一个 case 对应的返回值,而是继续匹配,所有的case都匹配不成功则只返回默认 case。

public class Test {
   public static void main(String args[]){
      int i = 5;
      switch(i){
         case 0:
            System.out.println("0");
         case 1:
            System.out.println("1");
         case 2:
            System.out.println("2");
         default:
            System.out.println("default");
      }
   }
}

以上代码编译运行结果如下:

default

情况2:如果当前匹配成功的 case 语句块没有 break 语句,则从当前 case 开始,后续所有 case 的值都会输出,如果后续的 case 语句块有 break 语句则会跳出判断。

public class Test {
   public static void main(String args[]){
      int i = 1;
      switch(i){
         case 0:
            System.out.println("0");
         case 1:
            System.out.println("1");
         case 2:
            System.out.println("2");
         case 3:
            System.out.println("3");
             break;
         default:
            System.out.println("default");
      }
   }
}

以上代码编译运行结果如下:

1
2
3

switch中有return的实例

public class Test {
   public static void main(String args[]){
      int i = 1;
      switch(i){
         case 0:
            System.out.println("0");
             break;
         case 1:
            System.out.println("1");
             break;
         case 2:
            System.out.println("2");
            return;
         case 3:
            System.out.println("3");
             break;
         default:
            System.out.println("default");
            break;
      }
     System.out.println("执行了switch语句");
   }
}

以上代码编译运行结果如下: 可以看到main方法已经被直接终结了,不会继续后面的操作了

1

真实实战案列

三目表达式

Java 提供了一个特别的三元运算符(也叫三目运算符)经常用于取代某个类型的 if-then-else 语句。条件运算符的符号表示为“?:”,使用该运算符时需要有三个操作数,因此称其为三目运算符。使用条件运算符的一般语法结构为:

result = <expression> ? <statement1> : <statement3>;

其中,expression 是一个布尔表达式。当 expression 为真时,执行 statement1, 否则就执行 statement3。此三元运算符要求返回一个结果,因此要实现简单的二分支程序,即可使用该条件运算符。 我们往往会用一个方法去表示expression表达式,JAVA的方法可以直接当做

expression (只要返回值是布尔类型即可)

下面是一个使用条件运算符的示例。

int x,y,z;
x = 6,y = 2;
z = x>y ? x-y : x+y;

在这里要计算 z 的值,首先要判断 x>y 表达的值,如果为 true,z 的值为 x-y;否则 z 的值为 x+y。很明显 x>y 表达式结果为 true,所以 z 的值为 4。

技巧:可以将条件运算符理解为 if-else 语句的简化形式,在使用较为简单的表达式时,使用该运算符能够简化程序代码,使程序更加易读。

我们往往会用一个java方法去表示expression表达式,JAVA的方法可以直接当做

expression (只要返回值是布尔类型即可)如以下示例

   
    public static void main(String[] args) {
        int a=1;
        String b=check(a)?"a大于1":"a小于等于1";
        System.out.println(b);
    }




    public static boolean check(int a){
        if(a>1){
            return true;
        }else{
            return false;
        }
    }
   
//打印结果 a小于等于1

IOUtils

IO流在我们日常工作中也用得比较多,尽管java已经给我们提供了丰富的API。

但我们不得不每次读取文件,或者写入文件之后,写一些重复的的代码。手动在finally代码块中关闭流,不然可能会造成内存溢出。

有个好消息是:如果你使用org.apache.commons.io包下的IOUtils类,会节省大量的时间。

<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.5</version>
</dependency>

8.1 读取文件

如果你想将某个txt文件中的数据,读取到字符串当中,可以使用IOUtils类的toString方法。例如:

String str = IOUtils.toString(new FileInputStream("/temp/a.txt"), StandardCharsets.UTF_8);
System.out.println(str);

8.2 写入文件

如果你想将某个字符串的内容,写入到指定文件当中,可以使用IOUtils类的write方法。例如:

String str = "abcde";


IOUtils.write(str, new FileOutputStream("/temp/b.tx"), StandardCharsets.UTF_8);

8.3 文件拷贝

如果你想将某个文件中的所有内容,都拷贝到另一个文件当中,可以使用IOUtils类的copy方法。例如:

IOUtils.copy(new FileInputStream("/temp/a.txt"), new FileOutputStream("/temp/b.txt"));

8.4 读取文件内容到字节数组

如果你想将某个文件中的内容,读取字节数组中,可以使用IOUtils类的toByteArray方法。例如:

byte[] bytes = IOUtils.toByteArray(new FileInputStream("/temp/a.txt"));

MultiValueMap

MultiValueMap 是什么 - 知乎 (zhihu.com)

简介:

即一个键对应多个值,Spring的内部实现是LinkedMultiValueMap

MultiValueMap 一个Key对应多个Value 是 属于Spring框架中的一个类,相比HashMap构造像Map<K, List<V>>或者Map<K, Set<V>>这样比较复杂的集合类型的数据结构,MultiValueMap 来做相应的业务逻辑处理。那MultiValueMap 在合适不过,处理这样的场景MultiValueMap 的代码量会非常少.但是往往问题在于从List去转成Map<K, List<V>>或者MultiValueMap (利用JAVA8 流的group by)

使用示例:

1 MultiValueMap.add()往MultiValueMap添加一个键值对

MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("name","11");
params.add("name","22");
params.add("name","33");


String name = params.get("name").get(1);
System.out.println(name);


//打印结果 22

2 MultiValueMap.put()往MultiValueMap添加一个键值对,但是一个键对应多个值(即一个List)

MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("name","11");
params.add("name","22");
params.add("name","33");


List idList = new ArrayList<>();
idList.add("1122");
idList.add("33434");
params.put("name",idList);
String name2 = params.get("name").get(1);
System.out.println(name2);
//打印结果 33434

3 MultiValueMap.size()获取MultiValueMap中值的数量

数量这里不是普通Map那样简单的获取键值对的数量,由于这里一个键对应多个值,故这里的数量是指值的数量

MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("name","11");
params.add("name","22");
params.add("name","33");


List idList = new ArrayList<>();
idList.add("1122");
idList.add("33434");
params.put("name",idList);


System.out.println("size:"+params.size());

4 MultiValueMap.keySet(),MultiValueMap.values()-遍历MultiValueMap

//获取MultiValueMap中所有的key
Set<String> keySet = params.keySet();


for (String key : keySet) {


    //获取指定key对应的值
    List<String> values = params.get(key);


    for (String value : values) {


        System.out.println(key + ": " + value);


    }


}


//直接获取每个Key的所有的值
Collection<List<String>> valuesList = params.values();
for (List<String> values2 : valuesList) {
    System.out.println(values2);
}

5 MultiValueMap.get()-获取指定键(key)对应的所有值,返回值是List

  MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
 params.add("name","11");
  params.add("name","22");
    params.add("name","33");
      //获取指定key对应的值
    List<String> values = params.get(key);

使用场景

@import导入的实现了ImportSelector或者ImportBeanDefinitionRegistra接口的类中的实现方法

如下

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(UserSelectImport.class)
public @interface EnablaUserSelectImportStudy {


    public String className() default "";


}

public class UserSelectImport implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
     //获取@Import注解修饰的指定名称的注解 即@EnablaUserSelectImportStudy 
//key是被@Import注解修饰的注解中的属性名称,Object是对应属性的属性值(可以有多个-
//--比如属性值是一个数组或者集合,故这里用MultiValueMap去表示这个关系
  //用MultiValueMap那么不算属性值是集合数组还是单个元素,都可以表示,
  //-因为MultiValueMap可以表示一个key(键)对应多个值或者一个值
        MultiValueMap<String, Object> allAnnotationAttributes = annotationMetadata.getAllAnnotationAttributes("com.example.idempotent.annotation.EnablaUserSelectImportStudy");
        String[] result = new String[0]; ;
        if(MapUtils.isNotEmpty(allAnnotationAttributes)) {
  //遍历MultiValueMap中的每一个键值对,key是属性名,值是属性值
            for (Map.Entry<String, List<Object>> entry : allAnnotationAttributes.entrySet()) {
                String key = entry.getKey();
                //获取当前key的所有属性值
                List<Object> valueList = entry.getValue();
                if(CollectionUtils.isNotEmpty(valueList)){
                    System.out.println(key + ":" + valueList);
                    if(StringUtils.equals(key,"className")){
 //如果@EnablaUserSelectImportStudy 注解的className属性的值是xxrUser,则把xxrUser这个类交给Spring管理
                        
                        if(StringUtils.equals("xxrUser", valueList.get(0).toString())){
                            result= new String[]{"com.example.idempotent.xxrUser"};
 //如果@EnablaUserSelectImportStudy 注解的className属性的值是ljmUser,则把ljmUser这个类交给Spring管理
                        }else if(StringUtils.equals("ljmUser", valueList.get(0).toString())){
                            result= new String[]{"com.example.idempotent.ljmUser"};
                        }else{
                            throw new RuntimeException("沒有找到目标配置类");
                        }
                    }
                }
            }
        }
        return result;
    }
}

MultiMap 

简介

原理和使用和MultiValueMap非常相似,但是它是属于Guava中的类,也是表示一个键可以直接对应多个值

引入相关依赖

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>21.0</version>
</dependency>

multimap和MultiSet的继承结果很相似,只不过在上层的接口是Multimap不是Multiset。

Multimap的特点其实就是可以包含有几个重复Key的value,你可以put进入多个不同value但是相同的key,但是又不是让后面覆盖前面的内容。

它的业务场景:当你需要构造像Map<K, List<V>>或者Map<K, Set<V>>这样比较复杂的集合类型的数据结构,来做相应的业务逻辑处理。那Multimap或者MultiValueMap再合适不过。但是往往问题在于从List去转成Map<K, List<V>>或者Multimap(利用JAVA8 流的group by)

举例

        @Test
        public void testMultimap(){
        HashMultimap<Integer, Integer> map = HashMultimap.create();
        map.put(1, 2);
        map.put(1, 3);
        map.put(1, 2);
        map.put(2, 3);
        map.put(4, 2);
        map.put(4, 3);
        map.put(4, 2);
        map.put(4, 3);
        System.out.println(map.toString());
    }
}
/*输出结果:
 *{1=[2, 3], 2=[3], 4=[2, 3]}
 */

其实它会把相同key和value的值给覆盖起来,但是相同的key又可以保留不同的value。因为它的entry的实现是一个set,set会对相同的Entry<K,V>进行去重,所以会有这种情况。 

实际开发场景及常用方法

 (1)根据业务需要对下面的list数据根据name字段来进行分组:

[
    {
        "date":"2018-01-31",
        "name":"wuzhong",
        "socre":0.8
    },
    {
        "date":"2018-01-30",
        "name":"wuzhong",
        "socre":0.9
    },
    {
        "date":"2018-01-31",
        "name":"wuzhong2",
        "socre":0.8
    }
]

传统做法

//假设上述JSON中的值已经存在这个list中
List<Item> list ;


//Item就是封装的对象
Map<String,List<Item>> map = new HashMap<>();
for (Item item : list){
  List<Item> tmp = map.get(item.getName());
  if (null == tmp){
      tmp = new ArrayList<>();
      map.put(item.getName(),tmp);
  }
  tmp.add(item);
}

很简单, 但是代码量有点多,特别是需要判断List为null并初始化。

再用guava实现上述的功能:

Multimap<String,Item> multiMap = ArrayListMultimap.create();
for (Item item : list){
    multiMap.put(item.getName(),item);
}

代码量直接减少了一半,这就是实际开发中它发挥的作用。所有的guava的集合都有create()方法去初始化集合,这个好处就是比较简单,你不用重复泛型信息了。

常用方法

1 get ()-获取指定键(key)对应的所有值,返回值是List

            Multimap<String,String> multimap = ArrayListMultimap.create();


            multimap.put("lower", "a");
            multimap.put("lower", "b");
            multimap.put("lower", "c");


            multimap.put("upper", "A");
            multimap.put("upper", "B");


            List<String> lowerList = (List<String>)multimap.get("lower");
            //输出key为lower的list集合
            System.out.println("输出key为lower的list集合=========");
            System.out.println(lowerList.toString());
            lowerList.add("f");
            System.out.println(lowerList.toString());
            
 *输出key为lower的list集合=========
 * [a, b, c]
 * [a, b, c, f]

2 asMap()-把Multimap转为一个map

             Multimap<String,String> multimap = ArrayListMultimap.create();


            multimap.put("lower", "a");
            multimap.put("lower", "b");
            multimap.put("lower", "c");


            multimap.put("upper", "A");
            multimap.put("upper", "B");
       Map<String, Collection<String>> map = multimap.asMap();
            System.out.println("把Multimap转为一个map============");
            
            for (Map.Entry<String,  Collection<String>> entry : map.entrySet()) {
                String key = entry.getKey();
                Collection<String> value =  multimap.get(key);
                System.out.println(key + ":" + value);
            }
            
  把Multimap转为一个map============
 * lower:[a, b, c, f]
 * upper:[A, B]

3 遍历Multimap

     Multimap<String,String> multimap = ArrayListMultimap.create();


            multimap.put("lower", "a");
            multimap.put("lower", "b");
            multimap.put("lower", "c");


            multimap.put("upper", "A");
            multimap.put("upper", "B");
         System.out.println("获得所有Multimap的key值==========");
             
            Set<String> keys =  multimap.keySet();
            for(String key:keys){
                System.out.println(key);
            }


            System.out.println("输出Multimap所有的value值========");
            Collection<String> values = multimap.values();
            System.out.println(values);
            
    * 获得所有Multimap的key值==========
 * lower
 * upper
 * 输出Multimap所有的value值========
 * [a, b, c, f, A, B]

JAVA各个时间类型的转换(LocalDate与Date类型)

LocalDateTime转Date类型

要将LocalDateTime转换回java.util.Date,我们可以使用以下步骤:

1.使用atZone()方法将LocalDateTime转换为ZonedDateTime

2.将ZonedDateTime转换为Instant,并从中获取Date

LocalDateTime now = LocalDateTime.now();
Instant nowInstant = now.atZone(ZoneId.systemDefault()).toInstant();
Date from = Date.from(nowInstant);
System.out.println(now);
System.out.println(from);
//打印结果
2023-02-04T16:16:34.269
Sat Feb 04 16:16:34 CST 2023

LocalDate转Date

(224条消息) 【Java 8 新特性】Java LocalDate 转 Date_猫巳的博客-CSDN博客_localdate to date

1 使用LocalDate.atTime方法将该日期与指定的时间相结合(拼接),创建一个LocalDateTime

2.使用atZone()方法将LocalDateTime转换为ZonedDateTime 
3.将ZonedDateTime转换为Instant,并从中获取Date

LocalDate now = LocalDate.now();
System.out.println(now);
Instant instant = LocalDate.now().atTime(LocalTime.MIDNIGHT).atZone(ZoneId.systemDefault()).toInstant();
Date from = Date.from(instant);
System.out.println(from);
//打印结果
2023-02-04
Sat Feb 04 00:00:00 CST 2023

Date转换为LocalDateTime,LocalDate,LocalTime

Date date = new Date();
LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
System.out.println(date);
System.out.println(localDateTime);
//打印结果
Sat Feb 04 16:41:12 CST 2023
2023-02-04T16:41:12.657
 
Date date = new Date();
//ZonedDateTime类中有toLocalDate,toLocalDateTime,toLocalTime,故利用它可以把Date时间转为LocalDate或者LocalDateTime或者LocalTime
LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
System.out.println(date);
System.out.println(localDate);

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值