目录
1 org.apache.commons.lang3.StringUtils
2 org.apache.commons.collections4.CollectionUtils
3 org.apache.commons.collections4.MapUtils
4 org.springframework.beans.BeanUtils
Java内省机制:getPropertyDescriptors(Class clazz)
5 com.google.common.collect.Maps
6 com.google.common.collect.Lists
1 org.apache.commons.lang3.StringUtils
1.1 isBlank
字符串为null或""或字符串只含有空格返回true
public static boolean isBlank(final CharSequence cs) {
int strLen;
if (cs == null || (strLen = cs.length()) == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
//当前字符不是空格则返回false
if (!Character.isWhitespace(cs.charAt(i))) {
return false;
}
}
return true;
}
试一下:
- StringUtils.isBlank(""): true
- "".length: 0
- StringUtils.isBlank(" "): true
- " ".length: 1
- StringUtils.isBlank("bob"): false
- StringUtils.isBlank(" bob "): false
1.2 isEmpty
字符串为null或""返回true
public static boolean isEmpty(final CharSequence cs) {
return cs == null || cs.length() == 0;
}
1.3 blank系列
isAnyBlank:存在任意一个为blank
isNoneBlank:没有blank,非isAnyBlank
isAllBlank:全都是blank
// StringUtils.isAnyBlank(new String[] {}) = false
public static boolean isAnyBlank(final CharSequence... css) {
if (ArrayUtils.isEmpty(css)) {
return false;
}
for (final CharSequence cs : css){
if (isBlank(cs)) {
return true;
}
}
return false;
}
// StringUtils.isAllBlank(new String[] {}) = true
public static boolean isAllBlank(final CharSequence... css) {
if (ArrayUtils.isEmpty(css)) {
return true;
}
for (final CharSequence cs : css) {
if (isNotBlank(cs)) {
return false;
}
}
return true;
}
1.4 empty系列
类同1.3blank系列
1.5 trim
去掉前后的控制符(control characters, char <= 32),如果使用字符串的trim方法,str为null就会报错,StringUtils做了一层友好封装
// StringUtils.trim(" \b \t \n \f \r ") = ""
public static String trim(final String str) {
return str == null ? null : str.trim();
}
trimToEmpty:return str == null ? EMPTY : str.trim();
与trim不同的是,如果str为null,返回""
trimToNull:return isEmpty(trim(str)) ? null : trim(str);
与trim不同的是,若trim后的结果为empty,则返回null
1.6 isNumeric
检查CharSequence是否仅包含Unicode数字。小数点不是Unicode数字,并且返回false。
public static boolean isNumeric(final CharSequence cs) {
if (isEmpty(cs)) {
return false;
}
final int sz = cs.length();
for (int i = 0; i < sz; i++) {
if (!Character.isDigit(cs.charAt(i))) {
return false;
}
}
return true;
}
// 返回一个值,该值指示字符的常规类别
public static boolean isDigit(int codePoint) {
return getType(codePoint) == Character.DECIMAL_DIGIT_NUMBER;
}
/**
* General category "Nd" in the Unicode specification.
* @since 1.1
*/
public static final byte DECIMAL_DIGIT_NUMBER = 9;
Unicode是一个编码方案(字符集),Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,至于这个二进制代码如何存储则没有任何规定。它的想法很简单,就是为每个字符规定一个用来表示该字符的数字。
根据一定规则去给这些字符集分类,Unicode数字类的type就是DECIMAL_DIGIT_NUMBER,9
2 org.apache.commons.collections4.CollectionUtils
2.1 isEmpty
集合判空
public static boolean isEmpty(final Collection<?> coll) {
return coll == null || coll.isEmpty();
}
coll.isEmpty()是接口Collection的方法,根据不同实现类对象调用对应实现类的isEmpty()
3 org.apache.commons.collections4.MapUtils
2.1 isEmpty
类同2 CollectionUtils
public static boolean isEmpty(final Map<?,?> map) {
return map == null || map.isEmpty();
}
4 org.springframework.beans.BeanUtils
4.1 copyProperties
将给定源bean的属性值复制到目标bean中。
注意:只要属性匹配,源类和目标类就不必相互匹配,甚至不必彼此派生。 源Bean公开但目标Bean没有公开的任何Bean属性都将被忽略。
public static void copyProperties(Object source, Object target) throws BeansException {
copyProperties(source, target, null, (String[]) null);
}
看源码
private static void copyProperties(Object source, Object target, @Nullable Class<?> editable,
@Nullable String... ignoreProperties) throws BeansException {
Assert.notNull(source, "Source must not be null");
Assert.notNull(target, "Target must not be null");
Class<?> actualEditable = target.getClass();
// null
if (editable != null) {
if (!editable.isInstance(target)) {
throw new IllegalArgumentException("Target class [" + target.getClass().getName() +
"] not assignable to Editable class [" + editable.getName() + "]");
}
actualEditable = editable;
}
// 核心方法:检索给定类的JavaBeans:获取目标bean的所有属性
PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
// null
List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);
// 循环目标bean的所有属性
for (PropertyDescriptor targetPd : targetPds) {
Method writeMethod = targetPd.getWriteMethod();
if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
// 核心方法:获取targetPd对应源bean的属性
PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
if (sourcePd != null) {
Method readMethod = sourcePd.getReadMethod();
if (readMethod != null &&
ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
try {
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
readMethod.setAccessible(true);
}
// 读取源bean的sourcePd属性的值(调用源bean的getter方法)
Object value = readMethod.invoke(source);
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
writeMethod.setAccessible(true);
}
// 写入目标bean的targetPd属性(调用目标bean的setter方法)
writeMethod.invoke(target, value);
}
catch (Throwable ex) {
throw new FatalBeanException(
"Could not copy property '" + targetPd.getName() + "' from source to target", ex);
}
}
}
}
}
}
Java内省机制:getPropertyDescriptors(Class<?> clazz)
内省获取javaBean中的字段,通过获取强引用或者软引用或者新建立一个安全的缓存内省,最后返回的就是javaBean中的有get或set方法的字段,如下图,获取的第一个字段为class,因为Object有getClass方法,所以只有readMethod方法
所以实体类若没有用set或get方法是获取不到属性的,如下图,source实体类没有set或get方法,获取的PropertyDescriptor为null
遇到的问题:类的内部类不会被copy?
原因:对于两个实体类来说,两个内部类类型并不一样,如下图,所以不会被copy
ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())
Java内省机制了解下
内省机制:是对于java Bean
的缺省处理,既比如在一个实体类中,有nama、address属性,那么系统会默认在此类中会有get/set方法进行获得和设置这两个值的方法。通过类 Introspector 的 getBeanInfo方法 来获取某个对象的 BeanInfo 信息,然后通过 BeanInfo 来获取属性的描述器(PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的 getter/setter 方法,然后我们就可以通过反射机制来调用这些方法。
内省机制类介绍:
Introspector
:将JavaBean中
的属性封装起来进行操作。在程序把一个类当做JavaBean
来看,就是调用Introspector.getBeanInfo()
方法,得到的BeanInfo
对象封装了把这个类当做JavaBean
看的结果信息,即属性的信息
BeanInfo
:将类中的信息封装到BeanInfo
中,获得了BeanInfo
对象就相当于获得了类中的所有属性信息。调用getPropertyDescriptors()
方法获得属性描述器,即获得了所有的属性信息。调用
PropertyDescriptor
:PropertyDescriptor
实例封装了每个属性特有的一些性质,比如调用getReadMethod()
方法就能获得这个属性的get方法Method,调用getWriteMethod()
方法就能获得这个属性的set方法Method。
与反射的区别?(反射相关内容可见:反射)
反射是在运行状态把Java类中的各种成分映射成相应的Java类,可以动态的获取所有的属性以及动态调用任意一个方法,强调的是运行状态。
内省(IntroSpector)是是对于java Bean
的缺省处理,系统会默认在类中会有get/set方法进行获得和设置私有属性值的方法。BeanInfo用来暴露一个bean的属性、方法和事件,再去通过反射来操作。
5 com.google.common.collect.Maps
5.1 newHashMap
之前使用的Map map = new HashMap();Map.newHashMap只是将new HashMap<>()包了一层,比较简洁一点,没啥太大区别
public static <K, V> HashMap<K, V> newHashMap() {
return new HashMap<>();
}
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("name", "123");
Map<String, String> guavaMap = Maps.newHashMap();
guavaMap.put("sex", "111");
log.info(map.get("name"));
log.info(guavaMap.get("sex"));
}
6 com.google.common.collect.Lists
6.1 newArrayList
与Maps不同的是,Lists提供了Lists.newArrayList(T... elements);
@SafeVarargs
public static <T> ArrayList<T> newArrayList(T... elements) {
if (elements == null) {
return null;
}
ArrayList<T> list = newArrayList();
java.util.Collections.addAll(list, elements);
return list;
}
public static <T> ArrayList<T> newArrayList() {
return new ArrayList<>();
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
List<Integer> guavaList = Lists.newArrayList(1,2);
log.info(list.toString());
log.info(guavaList.toString());
}