安卓开发中日期格式化工具类封装建议

安卓开发中日期格式化工具类封装建议

日期格式化是我们日常开发中很常见的操作。但是系统给我们建议用的api看的我是眼花缭乱,什么getDateInstance(),getDateTimeInstance()…看完之后一头雾水,完全不知道它们到底有多大差别。所以我打算重新封装一下这个操作。

众所周知,我们可爱的小伙伴SimpleDateFormat是线程不安全的。所以我们需要借助TreadLocal来保证每个线程的SimpleDateFormat的唯一性。如果你不知道什么是TeadLocal,建议你先去了解一下。

第一步我们先搞个单例模式,并声明一个日期格式化类的缓存类。当然这里的LruCache换成Map也可以,但是在安卓开发中内存是很宝贵的,LruCache对内存会更加友好一点。

public class DateFormatHelper {
    /**
     * 默认缓存的日期格式器长度,可根据实际使用情况修改此值
     */
    private static final int DEFAULT_FORMATTER_CACHE_LENGTH = 5;
    /**
     * 用于保存我们的日期格式器
     */
    private final LruCache<String, ThreadLocal<SimpleDateFormat>> dateFormatterCache;

    private DateFormatHelper() {
        dateFormatterCache = new LruCache<>(DEFAULT_FORMATTER_CACHE_LENGTH);
    }

    private static final class InstanceHolder {
        private static final DateFormatHelper INSTANCE = new DateFormatHelper();
    }

    public static DateFormatHelper getInstance() {
        return InstanceHolder.INSTANCE;
    }
}

然后把咋们最喜欢用的format方法和parse方法也在我们这个DateFormatHelper搞一个。

public class DateFormatHelper {
    ............

    /**
     * 日期格式化方法
     *
     * @param date    待格式化的日期
     * @param pattern 日期的指定格式
     * @return 格式化之后的日期
     */
    public String format(Date date, String pattern) {
        ThreadLocal<SimpleDateFormat> dateFormatterThreadLocal = dateFormatterCache.get(pattern);
        if (null == dateFormatterThreadLocal) {
            dateFormatterThreadLocal = new ThreadLocal<SimpleDateFormat>() {
                @Override
                protected SimpleDateFormat initialValue() {
                    return new SimpleDateFormat(pattern);
                }
            };
            dateFormatterCache.put(pattern, dateFormatterThreadLocal);
        }
        SimpleDateFormat targetDateFormatter = dateFormatterThreadLocal.get();
        return targetDateFormatter.format(date);
    }

    /**
     * 解析字符串为Date对象
     *
     * @param source  待解析的字符串
     * @param pattern 字符串的格式
     * @return 解析好的日期
     * @throws ParseException 解析时可能抛出的异常
     */
    public Date parse(String source, String pattern) throws ParseException {
        ThreadLocal<SimpleDateFormat> dateFormatterThreadLocal = dateFormatterCache.get(pattern);
        if (null == dateFormatterThreadLocal) {
            dateFormatterThreadLocal = new ThreadLocal<SimpleDateFormat>() {
                @Override
                protected SimpleDateFormat initialValue() {
                    return new SimpleDateFormat(pattern);
                }
            };
            dateFormatterCache.put(pattern, dateFormatterThreadLocal);
        }
        SimpleDateFormat targetDateFormatter = dateFormatterThreadLocal.get();
        return targetDateFormatter.parse(source);
    }
}

很明显,调用SimpleDateFormat的format和parse之前的代码都是重复的。所以我们这里抽离一个方法获取SimpleDateFormat。

public class DateFormatHelper {
    ............
    /**
     * 日期格式化方法
     *
     * @param date    待格式化的日期
     * @param pattern 日期的指定格式
     * @return 格式化之后的日期
     */
    public String format(Date date, String pattern) {
        SimpleDateFormat targetDateFormatter = getDateFormatterByPattern(pattern);
        return targetDateFormatter.format(date);
    }

    /**
     * 解析字符串为Date对象
     *
     * @param source  待解析的字符串
     * @param pattern 字符串的格式
     * @return 解析好的日期
     * @throws ParseException 解析时可能抛出的异常
     */
    public Date parse(String source, String pattern) throws ParseException {
        SimpleDateFormat targetDateFormatter = getDateFormatterByPattern(pattern);
        return targetDateFormatter.parse(source);
    }

    /**
     * 根据日期格式生成SimpleDateFormat
     * @param pattern 日期格式
     * @return 生成的SimpleDateFormat
     */
    private SimpleDateFormat getDateFormatterByPattern(String pattern) {
        ThreadLocal<SimpleDateFormat> dateFormatterThreadLocal = dateFormatterCache.get(pattern);
        if (null == dateFormatterThreadLocal) {
            dateFormatterThreadLocal = new ThreadLocal<SimpleDateFormat>() {
                @Override
                protected SimpleDateFormat initialValue() {
                    return new SimpleDateFormat(pattern);
                }
            };
            dateFormatterCache.put(pattern, dateFormatterThreadLocal);
        }
        return dateFormatterThreadLocal.get();
    }
}

这里的getDateFormatterByPattern还有点问题就是在多线程并发调用的情况下可能导致一个pattern put了多个dateFormatterThreadLocal,所以我们这里加个锁,来个双重非空判断。

public class DateFormatHelper {
    private static final Object lockObj = new Object();
    ............
    private SimpleDateFormat getDateFormatterByPattern(String pattern) {
        ThreadLocal<SimpleDateFormat> dateFormatterThreadLocal = dateFormatterCache.get(pattern);
        if (null == dateFormatterThreadLocal) {
            synchronized (lockObj) {
                dateFormatterThreadLocal = dateFormatterCache.get(pattern);
                if (null == dateFormatterThreadLocal) {
                    dateFormatterThreadLocal = ThreadLocal.withInitial(() -> new SimpleDateFormat(pattern));
                    dateFormatterCache.put(pattern, dateFormatterThreadLocal);
                }
            }
        }
        return dateFormatterThreadLocal.get();
    }
}

嗯,还有点不完美就是没有对参数进行非空判断。

public class DateFormatHelper {
    ............

    public String format(Date date, String pattern) {
        checkNotNull(date, "date不能为空");
        checkNotNull(pattern, "pattern均不能为空");
        ..........
    }

    public Date parse(String source, String pattern) throws ParseException {
        checkNotNull(source, "source不能为空");
        checkNotNull(pattern, "pattern不能为空");
        ........
    }
    
    /**
     * 检验的工具方法,若target为null,则抛异常
     * @param target 检测的目标
     * @param errorMessage target为null的时候抛出的异常提示
     */
    private static void checkNotNull(Object target, String errorMessage) {
        if (null == target) {
            throw new IllegalArgumentException(errorMessage);
        }
    }
}

嗯,基本已经完成了。然后我们在实际使用的时候定义一个pattern的常量类,我们实际使用的时候就这样调用。

String formatDate = DateFormatHelper.getInstance()
                .format(new Date(), DateFormatPatternConstants.DEFAULT_PATTERN);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值