feilong-core 亮点 1. 有常用专属工具类 (如处理日期的 `DateUtil`,处理集合的 `CollectionsUtil`,类型转换的`ConvertUtil` 等等等) 1. 有常用JAVA常量类 (如日期格式 `DatePattern`, 时间间隔 `TimeInterval` 等等等) 1. 不必要的`Exception` 转成`RuntimeException`,减少不必要的代码 1. 国内`中文注释`最完善的API 1. 有完善的单元测试 ## 1."看一眼就会爱上他"的方法 ### 1.1 ConvertUtil.toList(T...) 曾经,你调用某个api时,该api需要一个list参数, 但是你现在只有`单对象` 你需要这么写 ```JAVA List<Long> itemIds = new ArrayList<>(); itemIds.add(itemId); sdkItemManager.findItemImageByItemIds(itemIds); ``` 总感觉怪怪的, **很烦人** 你现在可以这么写 ```JAVA sdkItemManager.findItemImageByItemIds(ConvertUtil.toList(itemId)); ``` 一行代码,**轻松快乐的**写代码 同样,下面的代码 ```JAVA List<Long> skuIds = new ArrayList<>(); skuIds.add(9L); skuIds.add(10L); skuIds.add(13L); skuIds.add(18L); skuIds.add(20L); BundleValidateResult result = bundleManager.validateBundle(skuIds); ``` 依然,可以简写 ```JAVA List<Long> skuIds=ConvertUtil.toList(9L, 10L, 13L, 18L, 20L); BundleValidateResult result = bundleManager.validateBundle(skuIds); ``` 代码的可读性更高,**更简洁** **PS:**如果使用 [import static](https://docs.oracle.com/javase/1.5.0/docs/guide/language/static-import.html) 代码可以`更简洁` ### 1.2 CollectionsUtil.getPropertyValueList(Collection<O>, String) > 循环集合 `objectCollection`,取到对象指定的属性 `propertyName` 的值,拼成 `List`(ArrayList). 很多场合下,手头上有 `bean list`, 但是操作的时候,你可能需要使用每个bean里面的某个属性 **比如:** 提取SalesOrderCommand list里面的id属性组成 `List<Long>` ```JAVA List<SalesOrderCommand> salesOrderPage = sdkOrderDao.findOrdersWithOutPage(sorts, searchParam); //... List<Long> idList = new ArrayList<>(salesOrderPage.size()); for (SalesOrderCommand cmd : salesOrderPage){ idList.add(cmd.getId()); } //查询订单行 List<OrderLineCommand> allLineList = sdkOrderLineDao.findOrderDetailListByOrderIds(idList); ``` 这段代码,可以一行代码搞定 ```JAVA 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 exception` 和 `uncheckedException` 之分,也就是我们常说的 `RuntimeException`和 `Exception` `checked exception`有其使用场景,但是我们日常开发过程中,并没有对他做特殊的代码处理 比如,大部分小伙伴的代码是这样的: ```JAVA 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` ```JAVA public ContactCommand toContactCommand(ContactCommand command){ com.feilong.core.bean.BeanUtil.copyProperties(command, this); return command; } ``` 当然,如果你确定copy的对象相同属性名称的`类型是一致`的, 你可以使用 `PropertyUtil` ,可以有效的避免不必要的类型转换,提高效率 **代码简洁**,而且内部包装成的是自定义的 `BeanOperationException`(`RuntimeException`),如果需要特殊处理,依然可以 `try...catch...` ## 3. 有丰富的javadoc 调用方法的时候,可以清晰的感知这个方法的 `作用`,`示例`,`说明点`,`参数`,`返回值`,`异常`等信息  **源码示例:** ```JAVA /** * 计算两个时间相差的的天数(<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)); } ``` 如果你使用maven的话,只需要在依赖的jar 右键, maven--> `download javadoc` 或者 `download sources` 会自动下载  ## 4. 每个方法均有完善的 junit test > 方法实现之后,有上述的javadoc 详细的描述这个方法的作用 特点,注意点等, 那么怎么证明你写的东西都是正确而胡编乱造的呢? 我们有详细的 `junit` 单元测试, 每次构建的时候,都会经过maven 的单元测试周期 比如 `MapUtilGetSubMapTest` ```JAVA 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")); } } ```