如何使代码足够精简-Guava

Guava是一种基于开源的Java库,其中包含谷歌正在由他们很多项目使用的很多核心库。这个库是为了方便编码,并减少编码错误。这个库提供用于集合,缓存,支持原语,并发性,常见注解,字符串处理,I/O和验证的实用方法。

将字符串根据分隔符拆分连接,如果单用Java实现可能要判断为null的情况,代码会有好几行,代码本省不复杂,使用Guava提供的流式风格Joiner,代码看起来精简了很多

 String result = Joiner.on(";").skipNulls().join(Arrays.asList("a", "b",null));

比如也可以将null替换为某个字符串

String result = Joiner.on(";").useForNull("hell").join(Arrays.asList("a",null, "b",null));

与Java中String 的split相似,但是提供更加丰富的功能,使用String中的split需要判断空格等情况,看Guava中实现

Splitter.on(";").trimResults().omitEmptyStrings().split("java; ;;db");

上面代码返回[ java, db]

主要方法:

方法描述示例
Splitter.on(char)使用单独的一个字符分隔指定序列Splitter.on(‘;’)
Splitter.on(CharMatcher)使用某类的字符分隔指定序列Splitter.on(CharMatcher.BREAKING_WHITE) Splitter.on(CharMatcher.anyOf(“;,.”))
Splitter.on(String)使用字符串分隔指定序列Splitter.on(“, “)
Splitter.on(Pattern) Splitter.onPattern(String)根据正则表达式分隔指定序列Splitter.onPattern(“\r?\n”)
Splitter.fixedLength(int)将指定序列分隔成指定长度的子串,最后一个子串可能小于指定的值,但永远不可能为空Splitter.fixedLength(3)

还有一些其他方法,如忽略空字符串,剔除空字符、剔除指定字符等

可以把CharMatcher直观的想象成是一个表示字符的特殊类,像数字或空格之类。实际上,CharMatcher就是一个字符的布尔判判断 — 它实现了Predicate<Character>接口,因为它太常用了,例如:所有空格,所有小写字母等,Guava才为字符提供了这个API。

CharMatcher的作用就是在一个字符序列上执行一系列的操作:裁剪,折叠,移除,保留等等。一个CharMatcher类型的对象表示:

  1. 一个“匹配”的字符由什么组成?
    有很多操作来回答这个问题。
  2. 对这些“匹配”的字符要做什么?
CharMatcher digit = CharMatcher.digit();
boolean isDigit = digit.matchesAnyOf("ssd"); //false
isDigit = digit.matchesAnyOf("111d") //true
isDigit = digit.matchesAllOf("111") //true
isDigit = digit.matchesAllOf("111d") //false

常用方法

方法描述
anyOf(CharSequence)包括想要匹配的所有字符。例如CharMatcher.anyOf("aeiou")匹配所有小写的元音字符
is(char)匹配指定的字符
inRange(char, char)匹配一个范围内的字符,例如CharMatcher.inRange('a', 'z')

更多方法参考doc文档

定义一些常量,比如

  public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
  public static final Charset UTF_8 = Charset.forName("UTF-8");
  public static final Charset UTF_16BE = Charset.forName("UTF-16BE");

防止我们在程序内部写成固定值

String s = new String("hello".getBytes(),"UTF-8");
//应该这样写
s = new String("hello".getBytes(),Charsets.UTF_8);

如果使用JDK>1.6 可以使用StandardCharsets中的常量!

程序中的检查经常用到,比如检查一个对象是否为空等,Guava提供了各种静态检查方法,每个方法有三个不同的变体

  • 无参的方法。
    如果有异常会直接抛出,不会有任何错误信息
  • 有一个Object参数的方法。
    如果有异常会直接抛出,使用Object.toString()作为错误信息
  • 一个String和一个可变的Object参数 只接受%s占位符
checkArgument(i < j, "Expected i < j, but %s > %s", i, j);

常用方法

签名描述失败时抛出异常
checkArgument(boolean)检查boolean是否为true,用于验证参数IllegalArgumentException
checkNotNull(T)检查参数是否为null,直接返回该参数,可以内联使用NullPointerException
checkState(boolean)检查Object的状态,不依赖于方法参数,例如检查Iterator是否在remove之前调用了nextIllegalStateException
checkElementIndex(int index, int size)检查index的索引处的元素是否在List/Array/String内,元素的索引从0(包括)到size(不包括),不需要直接传List/Array/String,传他们的长度即可,返回indexIndexOutOfBoundsException
checkPositionIndex(int index, int size)检查index是否是一个合法的位置索引,范围从0(包括)到size(包括),不需要直接传List/Array/String,传他们的长度即可,返回indexIndexOutOfBoundsException
checkPositionIndexes(int start, int end, int size)检查[start, end)的范围是否是List/Array/String的子集IndexOutOfBoundsException

Java中使用Map做缓存最大的缺点是我们无法控制内存占用大小,或者基于LinkedHashMap实现LRU算法,Guava考虑到了这点,提供了多种缓存回收策略,防止内存溢出,个人觉得这个很使用

  • 基于内存占用大小的回收

如果不希望缓存占用过大的内存空间,查看CacheBuilder.maximumSize(long)。最近最久未使用的key-value将被回收。注意:Cache可能在尚未达到此限制的时候就进行回收了,尤其当大小接近限制的时候。

  • 基于时间回收

Guava提供了两种基于时间的回收方式:

expireAfterAccess(long, TimeUnit),仅在最后一次读写访问之后在指定的时间后才会回收,回收顺序类似于基于大小的回收。

expireAfterWrite(long, TimeUnit),在key-value被创建、修改后经过指定的时间后被回收,这对于一段时间后缓存的数据已经无效的情况下非常有用。

常用方法

  • equal

如果一个对象的属性可能为null,实现Object.equals()就有点麻烦了,因为要单独的检查null的情况。使用Objects.equal()可以在可能为null的情况下执行equals判断而不抛出NullPointerException。

jects.equal("ac", "ac"); //true
Objects.equal(null, "ac"); //false
Objects.equal("ac", null); //false
Objects.equal(null, null); //true
  • compare/compareTo

直接实现Comparator或Comparable方法,在属性很多时,看起来很乱

Guava提供了ComparisonChain

ComparisonChain是惰性比较:它仅在找到非零值的时候才进行比较,完成后忽略后面的输入

blic int compareTo(Hello that) {
    return ComparisonChain.start()
        .compare(this.aString, that.aString)
        .compare(this.name, that.name)
        .compare(this.anEnum, that.anEnum, Ordering.nature().nullsFirst())
        .result();
}

这样流式的方式具有更好的可读性,不会导致意外的错误,除了必须的不会做任何额外的工作,足够精简

Java中通过返回Future实现异步编程,类似

    static final ExecutorService executorService = new ThreadPoolExecutor(10,20,1000, TimeUnit.SECONDS,new LinkedBlockingDeque<>(100));

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Future<String> future = executorService.submit(new Run());
        String result = future.get();
        System.out.println(result);
    }

    static class Run implements Callable<String>{
        @Override
        public String call() throws Exception {
            //do anything
            return "success";
        }
    }

但是future.get()还是阻塞的,所以还不算真正意义上的异步,Guava提供了ListeningExecutorService对 ExecutorService进行了包装,通过回调函数的方式,实现真正异步,即在方法执行完成后执行绑定的回调的函数,执行回调函数时任务之间不需要等待

  static final ExecutorService executorService = new ThreadPoolExecutor(10,20,1000, TimeUnit.SECONDS,new LinkedBlockingDeque<>(100));

    static final ExecutorService callbackExecutor = Executors.newSingleThreadExecutor();

    static ListeningExecutorService listeningExecutorService;

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        listeningExecutorService = MoreExecutors.listeningDecorator(executorService);
        ListenableFuture<String> listenableFuture = listeningExecutorService.submit(new Run());
        Futures.addCallback(listenableFuture, new FutureCallback<String>() {
            @Override
            public void onSuccess(@Nullable String result) {
                System.out.println(result);
            }

            @Override
            public void onFailure(Throwable t) {

            }
        },callbackExecutor);
    }

    static class Run implements Callable<String>{
        @Override
        public String call() throws Exception {
            //do anything
            return "success";
        }
    }

https://juejin.im/post/5eca6905f265da770f51f098

「点点赞赏,手留余香」

    还没有人赞赏,快来当第一个赞赏的人吧!
0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论