Skip to content
This repository has been archived by the owner on Aug 20, 2021. It is now read-only.

Reasons for use feilong core

feilong edited this page Nov 28, 2016 · 12 revisions

使用feilong-core的理由

  1. 有常用的工具类 (如 处理日期的 DateUtil,处理 集合 的 CollectionsUtil 等)
  2. 有常用的JAVA常量类 (如日期格式 DatePattern, 时间间隔 TimeInterval 等)
  3. 不必要的Exception 转成了RuntimeException,减少不必要的代码
  4. 国内中文注释最完善的API
  5. 有完善的单元测试

1."看一眼你就会爱上他"的方法

1.1 ConvertUtil.toList(T...)

曾经,你调用某个api时,该api需要一个list参数, 但是你现在只有单对象

你需要这么写

	List<Long> itemIds = new ArrayList<Long>();
	itemIds.add(itemId);
	
	sdkItemManager.findItemImageByItemIds(itemIds, null);

总感觉怪怪的, 很烦人

你现在可以这么写

	sdkItemManager.findItemImageByItemIds(ConvertUtil.toList(itemId), null);

一行代码,轻松快乐的写代码

同样,下面的代码

	List<Long> skuIds = new ArrayList<Long>();
	skuIds.add(9L);
	skuIds.add(10L);
	skuIds.add(13L);
	skuIds.add(18L);
	skuIds.add(20L);
	BundleValidateResult result = bundleManager.validateBundle(3L, skuIds, 10);

依然,可以简写

	List<Long> skuIds=ConvertUtil.toList(9L, 10L, 13L, 18L, 20L);
	BundleValidateResult result = bundleManager.validateBundle(3L, skuIds, 10);

代码的可读性更高,更简洁

**PS:**如果使用 import static 代码可以更简洁

1.2 CollectionsUtil.getPropertyValueList(Collection, String)

循环集合 objectCollection,取到对象指定的属性 propertyName 的值,拼成 List(ArrayList).

很多场合下,手头上有 bean list, 但是操作的时候,你可能需要使用每个bean里面的某个属性

比如: 提取SalesOrderCommand list里面的id属性组成 List<Long>

		List<SalesOrderCommand> salesOrderPage = sdkOrderDao.findOrdersWithOutPage(sorts, searchParam);

		//...

        List<Long> idList = new ArrayList<Long>(salesOrderPage.size());
        for (SalesOrderCommand cmd : salesOrderPage){
            idList.add(cmd.getId());
        }

		//查询订单行
        List<OrderLineCommand> allLineList = sdkOrderLineDao.findOrderDetailListByOrderIds(idList);

这段代码,可以一行代码搞定

		List<SalesOrderCommand> salesOrderPage = sdkOrderDao.findOrdersWithOutPage(sorts, searchParam);

		//...

		List<Long> idList =CollectionsUtil.getPropertyValueList(salesOrderPage, "id");

		//查询订单行
        List<OrderLineCommand> allLineList = sdkOrderLineDao.findOrderDetailListByOrderIds(idList);

PS: 相似的方法,还有 CollectionsUtil.getPropertyValueSet(Collection<O>, String) 以及 CollectionsUtil.getPropertyValueMap(Collection<O>, String, String)

2.不能不说的异常处理

众所周知,JAVA 有 checked exceptionuncheckedException 之分,也就是我们常说的 RuntimeExceptionException

checked exception有其使用场景,但是我们日常开发过程中,并没有对他做特殊的代码处理

比如,大部分小伙伴的代码是这样的:

	public ContactCommand toContactCommand(ContactCommand command) {
		try {
			BeanUtils.copyProperties(command, this);
		} catch (Exception e){
			LOGGER.error("", e);
			//or e.printStackTrace();
		}
		return command;
	}

其实细究下来,上述代码是不合理的, 如果转换的时候出现了异常,这里就会出现数据没有转换过去的情况,

这理论上是 RuntimeException,但是 org.apache.commons.beanutils.BeanUtils 里面使用的是Exception, 所以小伙伴不能不try... catch一下,可是 catch 代码里面有可能仅仅写了log记录,这有可能会出现逻辑问题(本来需要抛出异常让事务回滚)

这时可以使用 com.feilong.core.bean.BeanUtil

    public ContactCommand toContactCommand(ContactCommand command){
        com.feilong.core.bean.BeanUtil.copyProperties(command, this);
        return command;
    }

当然,如果你确定copy的对象相同属性名称的类型是一致的, 你可以使用 PropertyUtil ,可以有效的避免不必要的类型转换,提高效率

代码简洁,而且内部包装成的是自定义的 BeanOperationException(RuntimeException),如果需要特殊处理,依然可以 try...catch...

3. 有丰富的javadoc

调用方法的时候,可以清晰的感知这个方法的 作用,示例,说明点,参数,返回值,异常等信息

源码示例:

    /**
     * 计算两个时间相差的的天数(<span style="color:red">绝对值</span>).
     * 
     * <h3>说明:</h3>
     * <blockquote>
     * <p>
     * 值=两个时间相差毫秒的绝对值/{@link TimeInterval#MILLISECOND_PER_DAY}
     * </p>
     * </blockquote>
     * 
     * <h3>示例:</h3>
     * 
     * <blockquote>
     * 
     * <pre class="code">
     * DateExtensionUtil.getIntervalDay(
     *      toDate("2008-08-24",COMMON_DATE),
     *      toDate("2008-08-27",COMMON_DATE)) = 3
     * 
     * DateExtensionUtil.getIntervalDay(
     *      toDate("2016-08-21 12:00:00",COMMON_DATE_AND_TIME),
     *      toDate("2016-08-22 11:00:00",COMMON_DATE_AND_TIME)) = 0
     * 
     * DateExtensionUtil.getIntervalDay(
     *      toDate("2016-08-21",COMMON_DATE),
     *      toDate("2016-08-22",COMMON_DATE)) = 1
     *      
     * DateExtensionUtil.getIntervalDay(
     *      toDate("2016-02-28",COMMON_DATE),
     *      toDate("2016-03-02",COMMON_DATE)) = 3
     * 
     * DateExtensionUtil.getIntervalDay(
     *      toDate("2016-08-31",COMMON_DATE),
     *      toDate("2016-09-02",COMMON_DATE)) = 2
     * 
     * </pre>
     * 
     * </blockquote>
     * 
     * @param date1
     *            date1
     * @param date2
     *            date2
     * @return 如果 <code>date1</code> 是null,抛出 {@link NullPointerException}<br>
     *         如果 <code>date2</code> 是null,抛出 {@link NullPointerException}
     * @see #getIntervalTime(Date, Date)
     * @see #getIntervalDay(long)
     * @since 1.6.0
     */
    public static int getIntervalDay(Date date1,Date date2){
        return getIntervalDay(getIntervalTime(date1, date2));
    }

4. 每个方法均有完善的 junit test

方法实现之后,有上述的javadoc 详细的描述这个方法的作用 特点,注意点等, 那么怎么证明你写的东西都是正确而胡编乱造的呢?

我们有详细的 junit 单元测试, 每次构建的时候,都会经过maven 的单元测试周期

比如 MapUtilGetSubMapTest

	package com.feilong.core.util.maputiltest;
	
	import static java.util.Collections.emptyMap;
	import static org.hamcrest.Matchers.allOf;
	import static org.hamcrest.Matchers.hasEntry;
	import static org.hamcrest.Matchers.hasKey;
	import static org.hamcrest.Matchers.not;
	import static org.junit.Assert.assertEquals;
	import static org.junit.Assert.assertThat;
	
	import java.util.HashMap;
	import java.util.Map;
	
	import org.junit.Test;
	
	import com.feilong.core.util.MapUtil;
	
	public class MapUtilGetSubMapTest{
	
	    /**
	     * Test get sub map.
	     */
	    @Test
	    public void testGetSubMap(){
	        Map<String, Integer> map = new HashMap<String, Integer>();
	        map.put("a", 3007);
	        map.put("b", 3001);
	        map.put("c", 3001);
	        map.put("d", 3003);
	        Map<String, Integer> subMap = MapUtil.getSubMap(map, "a", "c");
	        assertThat(subMap, allOf(hasEntry("a", 3007), hasEntry("c", 3001), not(hasKey("b")), not(hasKey("d"))));
	    }
	
	    /**
	     * Test get sub map 1.
	     */
	    @Test
	    public void testGetSubMap1(){
	        Map<String, Integer> map = new HashMap<String, Integer>();
	        map.put("a", 3007);
	        map.put("b", 3001);
	        map.put("c", 3001);
	        map.put("d", 3003);
	        Map<String, Integer> subMap = MapUtil.getSubMap(map, "a", "c", "f");
	        assertThat(subMap, allOf(hasEntry("a", 3007), hasEntry("c", 3001), not(hasKey("b")), not(hasKey("d"))));
	    }
	
	    /**
	     * Test get sub map null keys.
	     */
	    @Test
	    public void testGetSubMapNullKeys(){
	        Map<String, Integer> map = new HashMap<String, Integer>();
	        map.put("a", 3007);
	        map.put("b", 3001);
	        map.put("c", 3001);
	        map.put("d", 3003);
	        assertEquals(map, MapUtil.getSubMap(map, null));
	    }
	
	    /**
	     * Test get sub map empty keys.
	     */
	    @Test
	    public void testGetSubMapEmptyKeys(){
	        Map<String, Integer> map = new HashMap<String, Integer>();
	        map.put("a", 3007);
	        map.put("b", 3001);
	        map.put("c", 3001);
	        map.put("d", 3003);
	        assertEquals(map, MapUtil.getSubMap(map));
	    }
	
	    /**
	     * Test get sub map null map.
	     */
	    @Test
	    public void testGetSubMapNullMap(){
	        assertEquals(emptyMap(), MapUtil.getSubMap(null, "a", "c"));
	    }
	
	    /**
	     * Test get sub map empty map.
	     */
	    @Test
	    public void testGetSubMapEmptyMap(){
	        assertEquals(emptyMap(), MapUtil.getSubMap(new HashMap<>(), "a", "c"));
	        assertEquals(emptyMap(), MapUtil.getSubMap(emptyMap(), "a", "c"));
	    }
	}