轮子--实用工具类

252 阅读8分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第29天,点击查看活动详情

学习使用常用工具类。

java常用工具类

熟练使用工具类,避免重复造轮子

Collections

java.util包下的`Collections类,该类主要用于操作集合。和Collection接口不同,Collections类一般用来操作实现Collection接口的类。

排序

Collections类提供了对List<>集合进行排序的api。

  • 可自定义比较器Comparator。默认升序排序
  • reverse会将集合倒置,配合升序排序,可以实现降序排序 底层使用的Arrays.sort(a, (Comparator) c)方法
/**
* 生成10个随机数在 start到end之前的数字
*
* @param count
* @param start
* @param end
* @return
*/
public List<Integer> createRandomCollection(int count, int start, int end) {
  //检查count大于0
  Assert.check(count > 0);
  List<Integer> list = new ArrayList<>();
  for (int i = 0; i < count; i++) {
    list.add((int) (Math.random() * (end - start)) + start);
  }
  return list;
}
/**
 * 使用CollectionS对List进行排序
 */
@Test
public void collectionsSort() {

    List<Integer> integerList = createRandomCollection(20, 5, 20);
    System.out.println("原集合:=》\n" + integerList);
    //升序
    Collections.sort(integerList);
    System.out.println("降序排序后:=》\n" + integerList);
    //可自定义比较器
    Collections.sort(integerList, (val1, val2) -> {
        if (val1 > val2) {
            return -1;
        } else {
            return 1;
        }
    });
    System.out.println("自定义比较器实现升序:=》\n" + integerList);

    //将集合倒过来
    final List<Integer> randomCollection = createRandomCollection(20, 5, 20);
    System.out.println("愿集合:=》\n"+randomCollection);
    Collections.reverse(randomCollection);
    System.out.println("倒置后:=》\n"+randomCollection);

}

image-20220622020116927.png

获取极值

可以使用Collections获取集合的最大最小值。同样可以自定义比较器。

/**
 * 使用Collections获取集合的最大最小值
 */
@Test
public void getMaxAndMin() {
    List<Integer> integerList = createRandomCollection(20, 5, 20);
    System.out.println("集合:" + integerList);
    //最大值
    System.out.println("最大值:" + Collections.max(integerList));
    //最小值
    System.out.println("最小值:" + Collections.min(integerList));
}

image-20220622021111513.png

转换线程安全集合

java中除了Concurrent包下的集合,其余的大多数是非线程安全的,Collectios提供了可以将非线程安全的集合转化为线程安全的集合。

可以使用synchronizedXXXX方法转化为线程安全的集合,返回的集合类型是Collectios的静态内部类。但是不推荐,因为使用Collections转化的线程安全的集合都是使用Synchronized加锁实现的,性能不乐观。

/**
 * 将非线程安全的集合转化为线程安全的集合
 */
@Test
public void toConcurrentList() {
    final List<Integer> randomCollection = createRandomCollection(20, 5, 20);
    Collection<Integer> integers = Collections.synchronizedCollection(randomCollection);
}
判空后返回空集合而不是null

返回的集合是一个范型,不用手动转换

/**
 * 在判空后,需要返回空集合而不是null。可以借助Collections.emptyList()方法
 */
@Test
public void returnEmpty() {
    final List<Object> objects = Collections.emptyList();
}
二分查找
/**
 * 二分查找。给定集合,返回下标
 */
@Test
public void binarySearch() {
    final List<Integer> randomCollection = createRandomCollection(20, 5, 20);
    System.out.println(randomCollection);
    final int target = Collections.binarySearch(randomCollection, 10);
    System.out.println(target);
}

image-20220622023556956.png

转化为不可修改集合

如果某个流程不希望后续程序修改集合,可以使用此方法返回不可修改集合。

/**
 * 转化为不可修改集合
 */
@Test
public void toUnModify() {
    final List<Integer> randomCollection = createRandomCollection(20, 5, 20);
    final List<Integer> integerList = Collections.unmodifiableList(randomCollection);
    integerList.add(1);
}

image-20220622023924305.png


CollectionUtils

对集合操作,除了Collections工具类以外,CollectionUtils也很常用。

常用的两个分别是Spring.framework.utilorg.apache.commons.collections下的CollectionUtils。两者差不多,但是apache下的工具类功能更全。

我们以Spring框架为我们提供的工具类为例。

引入依赖:引入Spring上下文依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.18</version>
</dependency>
集合判空

spring为我们提供了isEmpty方法,而apache提供了isEmpty() 和isNotEmpty()方法。

/**
 * 集合判空,集合为null,或元素个数为0
 */
@Test
public void testCollectionIsEmpty() {
    final List<Integer> randomCollection = createRandomCollection(20, 5, 15);
    if (CollectionUtils.isEmpty(randomCollection)) {
        System.out.println("集合为空");
    }else {
        System.out.println("集合不为空");
    }
}

image.png

集合合并

对两个集合进行合并操作。比如取交集、并集。此方法spring未提供,需要引入apache包依赖

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.4</version>
</dependency>
/**
 * 集合合并
 * - 获取并集
 * - 获取交集
 * - 交集的补集
 * - 差集
 */
@Test
public void testCollectionMerge() {
    final List<Integer> randomCollection1 = createRandomCollection(5, 0, 9);
    final List<Integer> randomCollection2 = createRandomCollection(5, 0, 9);
    System.out.println("原集合1+=》\n" + randomCollection1);
    System.out.println("原集合2+=》\n" + randomCollection2);
    //并集
    final Collection<Integer> union = org.apache.commons.collections4.CollectionUtils.union(randomCollection1, randomCollection2);
    System.out.println("并集=》\n" + union);
    //交集
    final Collection<Integer> intersection = org.apache.commons.collections4.CollectionUtils.intersection(randomCollection1, randomCollection2);
    System.out.println("交集=》\n" + intersection);
    //交集的补集
    final Collection<Integer> disjunction = org.apache.commons.collections4.CollectionUtils.disjunction(randomCollection1, randomCollection2);
    System.out.println("补集=》\n" + disjunction);
    //差集
    final Collection<Integer> subtract = org.apache.commons.collections4.CollectionUtils.subtract(randomCollection1, randomCollection2);
    System.out.println("差集=》\n" + subtract);
}

image-20220622124248508.png


Lists

该工具类由Guaua工程提供,由Google工程师开发且广泛使用,使用轮子可以使得我们代码简洁。

依赖:

<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.1-jre</version>
</dependency>
创建空集合
/**
 * Lists创建空集合
 */
@Test
public void createEmptyList() {
    //空的LinkedList
    LinkedList<String> linkedList = Lists.newLinkedList();
    //空的ArrayList
    ArrayList<String> arrayList = Lists.newArrayList();
    //空的copyOnWriteArrayList,arrayList的线程安全版本
    CopyOnWriteArrayList<String> copyOnWriteArrayList = Lists.newCopyOnWriteArrayList();
}
快速初始化一个集合

借助可变长参数,快速初始化一个集合

/**
 * 可变长参数快速初始化集合
 * 可以是可变长参数
 * 可以是Iterable
 */
@Test
public void quickInitList() {
    ArrayList<Integer> arrayList = Lists.newArrayList(1, 2, 3, 4, 5);
    System.out.println(arrayList);
}
笛卡尔积
/**
 * 笛卡尔积
 * 这是一个可变长参数
 */
@Test
public void cartesianProduct() {
    List<Integer> randomCollection1 = CollectionUtilsTest.createRandomCollection(3, 0, 9);
    List<Integer> randomCollection2 = CollectionUtilsTest.createRandomCollection(3, 0, 9);
    System.out.println(Lists.cartesianProduct(randomCollection1, randomCollection2));
}

image-20220622195532153.png

集合拆分

将一个大集合拆分为多个小集合,需要指定原集合和拆分后集合的大小

/**
 * 拆分
 * <p>
 * 将一个大集合分割成落干个小集合,只需要制定集合和拆分集合大小即可
 */
@Test
public void splitList() {
    List<Integer> randomCollection1 = CollectionUtilsTest.createRandomCollection(10, 0, 9);
    System.out.println(randomCollection1);
    List<List<Integer>> lists = Lists.partition(randomCollection1, 3);
    System.out.println("拆分后:");
    for (List<Integer> list : lists) {
        System.out.println(list);
    }
}

image-20220622195714963.png

以流的形式转化

以流的形式将一个集合转化成另一个集合。以二进制流的形式转换,比循环处理效率高多了。

/**
 * 以流的形式讲一个集合转化成另一个集合
 */
@Test
public void transForm() {
    List<Integer> randomCollection1 = CollectionUtilsTest.createRandomCollection(10, 0, 9);
    final List<Integer> transform = Lists.transform(randomCollection1, element -> --element);
    System.out.println(randomCollection1);
    System.out.println(transform);

    System.out.println("当然Collection接口也提供了");
    List<Integer> collect = randomCollection1.stream().map(element -> --element).collect(Collectors.toList());
    System.out.println(collect);
}
颠倒集合
/**
 * 将集合颠倒
 */
@Test
public void reverse() {
    List<Integer> randomCollection1 = CollectionUtilsTest.createRandomCollection(10, 0, 9);
    System.out.println("原集合:=》" + randomCollection1);

    List<Integer> reverse = Lists.reverse(randomCollection1);
    System.out.println("颠倒后:=》" + reverse);

}

image-20220622211335193.png


Objects

Java.util包下的Objects类为我们提供了操作对象的工具类

判空

由于Objects只有当对象为NULL时才会判空,一般来说我们就用Spring提供的工具类BeanUtils来判空。

/**
 * 判空
 * 只有当对象为null时返回true
 */
@Test
public void isNull() {
    String string = new String();
    System.out.println(Objects.isNull(string));
}
/**
 * spring提供的判空
 */
@Test
public void springBeanUtils() {
    System.out.println(ObjectUtils.isEmpty(""));
}
为空抛异常

当对象为空时抛出异常,Assert也可以实现。

/**
 * 为空抛出异常
 */
@Test
public void ifNullThrow() {
    Object obj = null;
    //自定义异常信息
    Objects.requireNonNull(obj, "参数为空");
    //使用函数式接口,自定义异常
    Objects.requireNonNull(obj, () -> {
        return "参数为空";
    });
}

image-20220622213325224.png

判断两个对象是否相等
  • equals
  • deepEquals(可以判断数组)
/**
 * 判断两个对象是否相等
 * 判断逻辑:两个对象完全相等,或equals方法返回true
 */
@Test
public void isEquals() {
    String str1 = "abc";
    String str2 = "abc";
    String str3 = "123";
    System.out.println(Objects.equals(str1, str2));
    System.out.println(Objects.equals(str1, str3));
}

image-20220622213823873.png

好处:

避免空指针异常

/**
 * 使用Objects工具类,如果前者为null,是否抛出空指针异常
 * 
 * 不会
 */
@Test
public void shouldNullException() {
​
    Object obj1 = null;
    Object obj2 = new Object();
    //会抛出空指针异常
    obj1.equals(obj2);
    //使用Objects工具类则不会抛出异常
    Objects.equals(obj1, obj2);
​
}

比较的坑:

  • 基本数据类型自动拆箱空指针问题
  • 不同数据类型会装箱后再调用equals比较,数据类型不匹配直接返回false
/**
 * 对于基本数据类型比较的坑
 * 如果是基本数据类型的包装类型和基本数据类型比较的话,需要注意自动拆箱的空指针异常
 */
@Test
public void testSimpleType() {
    Integer i1 = null;
    int i2 = 0;
    //抛出空指针异常
    System.out.println(i1 == i2);
}
@Test
public void testSimpleType2() {
    long i1 = 1L;
    Integer i2 = 1;
    //true
    System.out.println(1 == 1L);
    //true
    System.out.println(i1 == i2);
    //false  这里是自动装箱的问题。long会装箱成Long 而不同类型的equals方法会返回false
    System.out.println(Objects.equals(i1, i2));
}
获取hashCode

使用ObjectHashCode()方法存在空指针危险,Objects则不会,当对象为空返回0.

就是加了一层判空逻辑

/**
 * 获取对象的hashCode
 */
@Test
public void getHashCode() {
    String str = "1223";
    //重写Object的hashCode方法,如多str为空会报空指针异常
    System.out.println(str.hashCode());
    //这里处理的好,为空返回0,不为空再调用hashCode方法
    System.out.println(Objects.hashCode(str));
}

BooleanUtils

布尔值工具类,同样的可以避免空指针异常。在Apache.common包下

可以返回非true,也就是false或者null

某些场景会对布尔值做转化,true - 1 false-0

int类型或String类型可以转化为Boolean类型

@Test
public void booleanUtils() {
  Boolean b = false;
  //将int转化为boolean
  System.out.println(BooleanUtils.toBoolean(1));
  System.out.println(BooleanUtils.toBoolean(1, 1, 0));
  //将String转化为boolean
  System.out.println(BooleanUtils.toBoolean("true"));
  System.out.println(BooleanUtils.toBoolean("abc","abc","123"));

  //将boolean转化为int或integer
  System.out.println(BooleanUtils.toInteger(b, 1, 0));
  //转化为String,可以制定 "true/"false"、"off"/"on"等等
  System.out.println(BooleanUtils.toStringOnOff(b));

  //判断某个布尔值是否为true或false即便为null也没事
  System.out.println(BooleanUtils.isFalse(b));
  System.out.println(BooleanUtils.isTrue(null));
  System.out.println(BooleanUtils.isNotTrue(null));
}

StringUtils

字符串工具类,在apache.common包下

对于字符串的处理时很频繁的,判空、截取、转换大小写等等

判空

一般使用isBlank方法,因为此方法会将 “ ”空行考虑进去

@Test
public void isEmpty() {
    //字符串对象为null或没有字符串长度为0
    System.out.println(StringUtils.isEmpty(""));
    System.out.println(StringUtils.isEmpty(" "));
    //判断字符串是否为空行
    System.out.println(StringUtils.isBlank(" "));
}
分隔字符串
/**
 * 分隔字符串
 */
@Test
public void split() {
    String str = "1。2。3。4。5。6。7。8。9";
    //使用String的Split当字符串对象为空时会抛出空指针异常
    System.out.println(Arrays.toString(str.split("。", 4)));

    //使用StringUtils避免空指针异常
    System.out.println(Arrays.toString(StringUtils.split(str, "。", 3)));
}

image-20220622224442299.png

判断字符串是否为纯数字

我们使用Integer.valueOf()方法之前可以使用,isNumeric(String)判断字符串是否为纯数字

/**
 * 判断给定的字符串是否为纯数字
 */
@Test
public void testIsNumeric() {

    String str1 = "123";
    String str2 = "0.123";
    String str3 = "0.123f";
    String str4 = "123L";

    System.out.println(str1+"=>"+StringUtils.isNumeric(str1));
    System.out.println(str2+"=>"+StringUtils.isNumeric(str2));
    System.out.println(str3+"=>"+StringUtils.isNumeric(str3));
    System.out.println(str4+"=>"+StringUtils.isNumeric(str4));

}

image-20220622224849352.png

将集合拼接成字符串

首先会截取我们的数组,然后循环调用集合内对象的toString方法,用StringBuffer拼接起来返回。

/**
 * 将集合拼接成字符串,并自定义分隔符
 */
@Test
public void join() {
    ArrayList<Integer> list = Lists.newArrayList(1, 2, 3, 4, 5);
    final String join = StringUtils.join(list, ",", 0, list.size());
    System.out.println(join);
}

image-20220622225528384.png


Assert

Assert为断言的意思,很多情况下可以用于判段参数是否符合条件,否则抛出异常,且可以统一处理

参数不符合条件,会抛出java.lang.IllegalArgumentException异常

这里使用的是springframework.util下的工具类

判空
/**
* 断言为空或不为空
* - 对象
* - 集合
* - map
*/
@Test
public void testIsNull() {
  String str= null;
  Assert.notNull(str,"参数不可以为空");
  Assert.isNull(str,"参数必须为空");

  Lists.newArrayList(1,2,3,4);
  Assert.notEmpty((Object[]) null,"不可以为空");
}

image-20220622235110478.png

布尔值及其他
/**
 * 断言布尔值
 */
@Test
public void assertBoolean() {
    final List<Object> list = Lists.newArrayList();
    Assert.isTrue(!list.isEmpty(), "集合不可以为空");
}

/**
 * 断言是否符合类型
 */
@Test
public void assertInstance() {
    Assert.isInstanceOf(Integer.class, "abc", "类型不匹配");
    Assert.isAssignable(String.class, Object.class);
}

/**
 * 断言类型是否可以强转
 * - 存在父子关系
 * - 接口和其实现类
 */
@Test
public void assertAssignable() {
    //通过
    Assert.isAssignable(List.class, ArrayList.class);
    //通过
    Assert.isAssignable(Object.class, ArrayList.class);
    //可以
    Assert.isAssignable(Collection.class, List.class);
    //可以
    Assert.isAssignable(Collection.class, ArrayList.class);
    //不通过
    Assert.isAssignable(List.class, Object.class);
}