java技巧性技能点
哈哈哈,我胡汉三...不对本博主Fn又回来了,从事开发也几年了,最近看了点东西,闲着一起聊一聊呗,如有误,望指正。
自定义缓存
在现在的项目开发过程中,缓存是必不可少的一部分,无论是redis还是memcached,这些都是一些缓存需要的中间件,通常使用的mybatis,其中也有缓存的参与,因此这一部分的东西掌握是必不可少的,而项目是分布式部署的,那么可以使用JDK本身来自定义一个缓存容器,无论是LRU,FIFO,还是自定义二级缓存,都需要借助容器类来进行实现的,下面是一个可作为本地二级缓存使用的一个类,可自行扩展设计。
package com.fn.test.cache; import lombok.Data; import lombok.experimental.Accessors; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; /** * @Class : CacheManager * @Description :单个服务器内保存在JDK中,可做为二级缓存使用 * @Author | @Date : Fn-f | 2019-12-01 19:22:01 */ @Service("cacheManager") public class CacheManager { // 日志信息,真实项目中可使用LoggerFactory private static final Logger LOGGER = Logger.getLogger("CacheManager"); // cacheMap,作为缓存的容器 private Map<String, CacheItem> cache = new HashMap<String, CacheItem>(); /** * 添加值至本地缓存中 * @param key * @param val */ public void set (String key, Object val) { set(key, val, null); } /** * 添加值至本地缓存中,含过期时间(默认秒) * @param key * @param val * @param expired */ public void set (String key, Object val, Long expired) { LOGGER.info("cache set -> param: {" + key + ", " + val + ", " + expired + "}"); cache.put(key, new CacheItem().setObj(val).setTime(System.currentTimeMillis()).setExpired(expired)); } /** * 获取key对应的值 * @param key * @return */ public Object get (String key) { LOGGER.info("cache get -> param: {" + key + "}"); CacheItem item = cache.get(key); if (item != null && ( item.getExpired() == null || System.currentTimeMillis() < (item.getExpired() + item.getTime() * 1000L))) { return item.getObj(); } cache.remove(key); return null; } /** * 删除缓存中的key * @param key */ public void del (String key) { LOGGER.info("cache del -> param: {" + key + "}"); if (cache.get(key) != null) { cache.remove(key); } } @Data @Accessors(chain = true) private class CacheItem { // 当前存储对象 private Object obj; // 当前存储时间 private Long time; // 过期时间段 private Long expired; } }
函数式接口
JDK 8 发布已经好几年了,当前JDK12已经出来了,而对于java开发者来说,已经进入吃力学习,不断追赶,但是对于公司来说,大部分公司还是使用的是JDK 8 为主的,当然也有使用JDK 11 及以上版本的,毕竟JDK版本越高,其中无论是开发,还是优化都有一些调整,而目前使用的JDK 8 中的函数式编程,前面有一章节介绍了 Stream 流,这章也可看看,试用一下呗,自我感觉还是可以的,毕竟代码越少,程序越简洁,执行效率可能会更高(这一点先不用着急否认呐,毕竟荣誉代码与简洁代码的执行之间,编译还是优化都有很大的差别的,可以仔细研究呐),可以看看<Java 8 实战>这本书呐
package com.fn.test.util; import org.springframework.util.CollectionUtils; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; /** * @Class : StreamUtil * @Description :JDK 8 lambda使用,可自行扩展 * @Author | @Date : Fn-f | 2019-12-01 19:22:01 */ public class StreamUtil { /** * 满足某种函数返回指定数据集合信息,去重 * @param list * @param fn * @param <T> * @param <R> * @return */ public static <T, R> List<R> ids (List<T> list, Function<T, R> fn) { return !CollectionUtils.isEmpty(list) ? new ArrayList(list.stream().map(fn).collect(Collectors.toSet())) : Collections.EMPTY_LIST; } /** * 满足某种函数返回K-V信息,groupingBy返回信息为Map<T, List>,可能并非目前所需 * @param list * @param fn * @param <T> * @param <R> * @return */ public static <T, R> Map<T, R> map (List<R> list, Function<R, T> fn) { return !CollectionUtils.isEmpty(list) ? new ArrayList(list.stream().collect(Collectors.toMap(fn, i -> i)) : Collections.EMPTY_MAP; } /** * 可以指定其他类似 */ //public static test () { ... }
位运算(基础)
对于本博主这个非科班出身的程序员来说,这个熟悉,但是开发中使用还是没有太多机会的,当然也做过一些研究,什么补位,反码,补码等等吧,而现在看到其一个具体的应用,自我感觉记录下来,有遇到同样问题的开发人员可以借鉴参考呐
开发过程中,有可能会给某个东西贴标签,又或给某个人以某种身份,当有多中标签或身份时,难道要进行信息值累加吗? 这个时候用位运算是最好不过的。
package com.fn.test.demo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.Getter; import lombok.experimental.Accessors; /** * @Class : ItemInfo * @Description :商品信息:食物的味觉信息 * @Author | @Date : Fn-f | 2019-12-01 19:22:01 */ @Data @Accessors(chain = true) public class ItemInfo { private String name; private String price; private int tasteval; private Taste teste; /** * 味道信息 */ @Data static class Taste { private boolean sweet; private boolean acid; private boolean bitter; private boolean spicy; private boolean fragrant; private boolean smelly;
// 与运算,复boolean制 public Taste (int tasteval) { this.sweet = (tasteval & TasteEnum.SWEET.getCode()) > 0; this.acid = (tasteval & TasteEnum.ACID.getCode()) > 0; this.bitter = (tasteval & TasteEnum.BITTER.getCode()) > 0; this.spicy = (tasteval & TasteEnum.SMELLY.getCode()) > 0; this.fragrant = (tasteval & TasteEnum.FRAGRANT.getCode()) > 0; this.smelly = (tasteval & TasteEnum.SMELLY.getCode()) > 0; } } /** * 味道枚举信息 */ @Getter @AllArgsConstructor enum TasteEnum { SWEET ( 1 << 0, "甜"), ACID ( 1 << 1, "酸"), BITTER ( 1 << 2, "苦"), SPICY ( 1 << 3, "辣"), SALTY ( 1 << 4, "咸"), FRAGRANT ( 1 << 5, "香"), SMELLY ( 1 << 6, "臭"), ; private int code; private String desc; } /** * 测试 */ public static void main(String[] args) { ItemInfo apple = new ItemInfo(); apple.setName("苹果"); apple.setPrice("19.9元"); // 苹果味道:甜酸香 apple.setTasteval( TasteEnum.SWEET.getCode() + TasteEnum.ACID.getCode() + TasteEnum.FRAGRANT.getCode()); // 解析味道信息,进行展示等 apple.setTeste(new Taste(apple.getTasteval())); System.out.println(apple); // ItemInfo( // name=苹果, price=19.9元, tasteval=35, // teste=ItemInfo.Taste( // sweet=true, acid=true, bitter=false, // spicy=false, fragrant=true, smelly=false) // ) } }
随机数
随机数处理,可以与时间戳一起,增大随机性
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import java.util.Random; /** * @Class : Random * @Description :随机数 * @Author | @Date : Fn-f | 2019-12-01 19:10:01 */ public class R { private static final String BASE_NUM = "0123456789"; private static final String BASE_STR = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz"; /** * 获取指定大小的随机串(配合时间点来处理) * * @param base 指定字符源 * @param size 随机串大小 * @param zwst zero with start tag(从零开始标志) * @return String */ public static String random(String base, int size, boolean zwst) { if (size <= 0) { return ""; } StringBuilder s = new StringBuilder(); Random r = new Random(); for (int i = 0; i < size; i++) { char c; do { c = base.charAt(r.nextInt(base.length())); // 首位避免为零判断逻辑 } while (zwst && i == 0 && ((int) '0' == (int) c)); s.append(c); } return s.toString(); } public static void main(String[] args) { System.out.println(random(BASE_NUM, 9, false)); // 189640865 System.out.println(random(BASE_STR, 9, false)); // SvITxDRc3 } }
多线程使用(异步处理)
多线程的用法,有可能需要花费新的章节进行阐述,毕竟体系是十分胖庞大的,可以在项目中使用线程进行异步处理,可以使用线程池或相关的类来进行
比如使用 ThreadPoolManager()、Runnable()、Callable()、CompletableFuture.runAsync()、CompletableFuture.whenComplete()、等等处理形式,这一小节后续放置独立的一篇进行阐述。
枚举的别样用法
枚举中除了日常使用方式之外,其实质上可以当做一个类来进行使用,内部也可以指定方法,相应的属性处理对应的业务逻辑即可,这个也是一个优秀的操作。
视频剪辑工具FFMPEG
当有视频、音频、图片需要处理时,该工具能够帮助你得到自己想要的数据。尝试之前,必须要先安装该工具哟
工具类Hutool
简介:https://gitee.com/loolly/hutool/
Hutool简介: Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。 Hutool中的工具方法来自于每个用户的精雕细琢,它涵盖了Java开发底层代码中的方方面面,它既是大型项目开发中解决小问题的利器,也是小型项目中的效率担当; Hutool是项目中“util”包友好的替代,它节省了开发人员对项目中公用类和公用工具方法的封装时间,使开发专注于业务,同时可以最大限度的避免封装不完善带来的bug。 Hutool名称的由来 Hutool = Hu + tool,是原公司项目底层代码剥离后的开源库,“Hu”是公司名称的表示,tool表示工具。Hutool谐音“糊涂”,一方面简洁易懂,一方面寓意“难得糊涂”。 Hutool如何改变我们的coding方式 Hutool的目标是使用一个工具方法代替一段复杂代码,从而最大限度的避免“复制粘贴”代码的问题,彻底改变我们写代码的方式。 以计算MD5为例: 【以前】打开搜索引擎 -> 搜“Java MD5加密” -> 打开某篇博客-> 复制粘贴 -> 改改好用 【现在】引入Hutool -> SecureUtil.md5() Hutool的存在就是为了减少代码搜索成本,避免网络上参差不齐的代码出现导致的bug。
......
本文章后续不间断增新,望指正。
(愿你的每一行代码,都有让世界进步的力量 ------ fn)