Google Guava

  • 1.以面向对象思想处理字符串:Joiner/Splitter/CharMatcher
    // 连接器
    private static final Joiner joiner = Joiner.on(",").skipNulls();

    // 分割器
    private static final Splitter spliter = Splitter.on(",").trimResults().omitEmptyStrings();
    public static void main(String[] args) {
        //把集合数组中的元素join在一起
        String join = joiner.join(Lists.newArrayList("a", null, "b", "", "  "));
        System.out.println("join=" + join);

        for (String tmp : spliter.split(" a, b,  null  ,,")){
            System.out.println("|" + tmp + "|");
        }
    }

输出:
join=a,b,,
|a|
|b|
|null|

使用useForNull可以制定一个字符串替换null,而不是直接跳过null , 如下:

private static final Joiner joiner = Joiner.on(",").useForNull("wudy");

输出: join=a,wudy,b,,

使用空白字符分割

private static final Splitter spliter = Splitter.on(CharMatcher.WHITESPACE).trimResults().omitEmptyStrings();
for (String tmp : spliter.split(" a, b,  null  ,  ,")){
            System.out.println("|" + tmp + "|");
        }

输出:
|a,|
|b,|
|null|
|,|
|,|

按固定长度拆分,最后一段可能比给定长度短,但不会为空

private static final Splitter spliter = Splitter.fixedLength(3).trimResults().omitEmptyStrings();
for (String tmp : spliter.split(" a, b,  null  ,  ,   ")){
            System.out.println("|" + tmp + "|");
        }

输出:
|a,|
|b,|
|n|
|ull|
|,|
|,|

字符串匹配器

  private static final CharMatcher charMatcherDigit = CharMatcher.DIGIT;
  private static final CharMatcher charMatcherAny = CharMatcher.ANY;

  public static void main(String[] args) {
        //只保留匹配的字符,其他移除
        System.out.println("只保留字符串的数字=" + charMatcherDigit.retainFrom("ashbx78i~!"));
        System.out.println("移除字符串的数字=" + charMatcherDigit.removeFrom("ashbx78i~!"));
        System.out.println("用?替换数字=" + charMatcherDigit.replaceFrom("ashbx78i~!", "?"));
        System.out.println("在字母a~f范围或者等于n,全部替换为* |  " + charMatcherAny.inRange('a', 'f').or(charMatcherAny.is('n')).replaceFrom("xscfgvjhjkhdnass", "*"));
 }

输出:
只保留字符串的数字=78
移除字符串的数字=ashbxi~!
用?替换数字=ashbx??i~!
在字母a~f范围或者等于n,全部替换为* | xsgvjhjkh*ss

总结:

  • 1.对于Joiner,常用的方法是 跳过NULL元素:skipNulls() / 对于NULL元素使用其他替代:useForNull(String)
    1. 对于Splitter,常用的方法是:trimResults()/omitEmptyStrings()。注意拆分的方式,有字符串,还有正则,还有固定长度分割
  • 3.joiner实例总是不可变的。用来定义joiner目标语义的配置方法总会返回一个新的joiner实例。这使得joiner实例都是线程安全的,你可以将其定义为static final常量
  • 2.guava对JDK提供的原生类型操作进行了扩展
 public static void main(String[] args) {
        // 快速完成到集合的转换
        List list = Ints.asList(1,3,5,7,9);
        System.out.println(Ints.join(",", 1,3,1,4));

        // 原生类型的数组快速合并
        int[] intArray = Ints.concat(new int[]{1,2}, new int[]{3,4});
        System.out.println(intArray.length);

        //最大最小
        System.out.println("最大值=" + Ints.max(intArray) + "最小值=" + Ints.min(intArray));

        // 是否包含
        System.out.println("是否包含=" + Ints.contains(intArray, 1));

        // 集合到数组转换
        int[] intArr = Ints.toArray(list);
        
    }

输出:
1,3,1,4
4
最大值=4最小值=1
是否包含=true

总结: guava提供了Bytes/Shorts/Ints/Iongs/Floats/Doubles/Chars/Booleans这些基本数据类型的扩展支持

  • 3.对JDK集合的有效补充

灰色地带:Multiset
JDK的集合,提供了有序且可以重复的List,无序且不可以重复的Set。那这里其实对于集合涉及到了2个概念,一个order,一个dups。那么List vs Set,and then some ?

image.png

Multiset是什么,我想上面的图,你应该了解它的概念了。Multiset就是无序的,但是可以重复的集合,它就是游离在List/Set之间的“灰色地带”!
(至于有序的,不允许重复的集合嘛,guava还没有提供,当然在未来应该会提供UniqueList,我猜的,哈哈)
重点:Multiset自带一个有用的功能,就是可以跟踪每个对象的数量

   public static void main(String[] args) {
        HashMultiset hashMultiset = HashMultiset.create();
        hashMultiset.add("a");
        hashMultiset.add("a");
        hashMultiset.add("b");
        hashMultiset.add("c");
        hashMultiset.add("b");
        System.out.println("size=" + hashMultiset.size());
        System.out.println("元素a的出现次数" + hashMultiset.count("a"));
    }

输出:
size=5
元素a的出现次数2

  • 4.Immutable vs unmodifiable
// 先看一个unmodifiable的例子:
public static void main(String[] args) {
        List list = new ArrayList<>();
        list.add("a");
        list.add("b");

        List readOnlyList = Collections.unmodifiableList(list);
//        readOnlyList.add("c"); //java.lang.UnsupportedOperationException
        list.add("c");
        System.out.println(readOnlyList.size());  // 3
    }

你看到JDK提供的unmodifiable的缺陷了吗?
实际上,Collections.unmodifiableXxx所返回的集合和源集合是同一个对象,只不过可以对集合做出改变的API都被override,会抛出UnsupportedOperationException
也即是说我们改变源集合,导致不可变视图(unmodifiable View)也会发生变化。
当然,在不使用guava的情况下,我们是怎么避免上面的问题的呢?

public static void main(String[] args) {
        List list = new ArrayList<>();
        list.add("a");
        list.add("b");
        // new Object: copy (Defensive Copies,保护性拷贝)
        List readOnlyList = Collections.unmodifiableList(new ArrayList(list));
        list.add("c");
        System.out.println(readOnlyList.size());  // 2
    }

使用Guava方式
guava提供了很多Immutable集合,比如ImmutableList/ImmutableSet/ImmutableSortedSet/ImmutableMap, ImmutableCOPY阶段还考虑了线程的并发性等

public static void main(String[] args) {
        ImmutableList immutableList = ImmutableList.of("a", "b", "c");
//        immutableList.add("d"); //java.lang.UnsupportedOperationException
        ArrayList list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        ImmutableList immutableList1 = ImmutableList.copyOf(list);
        list.add("d");
        // 视图不会随着源数据而改变,guava只读设置安全可靠
        System.out.println("list size=" + list.size() + "  immutableList1 size=" + immutableList1.size() ); // list size=4  immutableList1 size=3
    }
// ImmutableMap例子
 ImmutableMap immutableMap = ImmutableMap.of("name", "wudy", "phone", "13074491521");
 immutableMap.put("address", "sz"); // java.lang.UnsupportedOperationException
  • 5.一对多: Multimap

JDK提供给我们的Map是一个键,一个值,一对一的,那么在实际开发中,显然存在一个KEY多个VALUE的情况(比如一个分类下的书本),我们往往这样表达:Map,好像有点臃肿!臃肿也就算了,更加不爽的事,我们还得判断KEY是否存在来决定是否new 一个LIST出来,有点麻烦!更加麻烦的事情还在后头,比如遍历,比如删除

 public static void main(String[] args) {
        Multimap multimap = ArrayListMultimap.create();
        multimap.put("phone", "13074491521");
        multimap.put("phone", "18973038382");
        multimap.put("name", "wudy");
        System.out.println(multimap.get("phone")); // [13074491521, 18973038382]
    }

友情提示下,guava所有的集合都有create方法,这样的好处在于简单,而且我们不必在重复泛型信息了。
get()/keys()/keySet()/values()/entries()/asMap()都是非常有用的返回view collection的方法。
Multimap的实现类有:ArrayListMultimap/HashMultimap/LinkedHashMultimap/TreeMultimap/ImmutableMultimap

  • 6.双向BiMap

JDK提供的MAP让我们可以find value by key,那么能不能通过find key by value呢,能不能KEYVALUE都是唯一的呢。这是一个双向的概念,即forward+backward
在实际场景中有这样的需求吗?比如通过用户ID找到mail,也需要通过mail找回用户名。没有guava的时候,我们需要create forward map AND create backward map,and now just let guava do that for you.

 public static void main(String[] args) {
        HashBiMap biMap = HashBiMap.create();
        biMap.put("wudy.yu", "13074491521");
        // value 重复会报错
//        biMap.put("peter.li", "13074491521"); // java.lang.IllegalArgumentException: value already present: 13074491521

        // 强制覆盖
        biMap.forcePut("peter.li", "13074491521");
        // 反转为 value => key
        System.out.println(biMap.inverse().get("13074491521")); // peter.li

    }

biMap / biMap.inverse() / biMap.inverse().inverse() 它们是什么关系呢?
你可以稍微看一下BiMap的源码实现,实际上,当你创建BiMap的时候,在内部维护了2个map,一个forward map,一个backward map,并且设置了它们之间的关系。
因此,biMap.inverse() != biMapbiMap.inverse().inverse() == biMap

  • 7.多个keyTable

我们知道数据库除了主键外,还提供了复合索引,而且实际中这样的多级关系查找也是比较多的,当然我们可以利用嵌套的Map来实现:Map>。为了让我们的代码看起来不那么丑陋,guava为我们提供了Table
Table涉及到3个概念:rowKey,columnKey,value,并提供了多种视图以及操作方法让你更加轻松的处理多个KEY的场景

 public static void main(String[] args) {
        Table table = HashBasedTable.create();
        table.put("wudy","语文", 100);
        table.put("wudy","数学", 80);
        table.put("wudy","英语", 90);
        table.put("wudy","计算机", 89);
        table.put("peter","地理", 13);
        table.put("peter","计算机", 73);

        //最小单位cell
        Set> set = table.cellSet();
        for (Table.Cell cell:set){
            System.out.println(cell.getRowKey() + "," + cell.getColumnKey() + "," + cell.getValue());
        }

        //row set
        Set rowSet = table.rowKeySet();
        System.out.println(rowSet); // [wudy, peter]

        //column set
        Set columnSet = table.columnKeySet();
        System.out.println(columnSet); // [数学, 语文, 英语, 计算机, 地理]

        //根据rowKey获取信息Map
        System.out.println(table.row("wudy")); // {数学=80, 语文=100, 英语=90, 计算机=89}

        //根据column获得信息Map
        System.out.println(table.column("计算机")); // {wudy=89, peter=73}

    }
  • 8.函数式编程:Functions
public static void main(String[] args) {
        ArrayList list = Lists.newArrayList("wudy.yu", "peter.li", "jack");
        Function f1 = new Function(){
            @Override
            public String apply(@Nullable String s) {
                return s.length() <= 5 ? s : s.substring(0,5);
            }
        };
        
        Function f2 = new Function() {
            @Nullable
            @Override
            public String apply(@Nullable String s) {
                return s.toUpperCase();
            }
        };
        Function f3 = Functions.compose(f1, f2);
        Collection collection = Collections2.transform(list, f3);
        for (String s:collection){
            System.out.println(s);
        }

    }

输出:
WUDY.
PETER
JACK

image.png

上面的代码是为了完成将List集合中的元素,先截取5个长度,然后转成大写。
函数式编程的好处在于在集合遍历操作中提供自定义Function的操作,比如transform转换。我们再也不需要一遍遍的遍历集合,显著的简化了代码!

  • 9.断言Predicate

Predicate最常用的功能就是运用在集合的过滤当中!

image.png

public static void main(String[] args) {
// 需要注意的是Lists并没有提供filter方法,不过你可以使用Collections2.filter完成!
        List list = Lists.newArrayList("wudy.yu", "peter.li", "moom");

        Collection collection = Collections2.filter(list, new Predicate() {
            @Override
            public boolean apply(@Nullable String s) {
                return new StringBuilder(s).reverse().toString().equals(s);
            }
        });

        for (String s:collection) {
            System.out.println(s); // moom
        }
    }
  • 10.check null and other:Optional、Preconditions

guava中,对于null的处理手段是快速失败,你可以看看guava的源码,很多方法的第一行就是:Preconditions.checkNotNull(elements);
要知道null是模糊的概念,是成功呢,还是失败呢,还是别的什么含义呢?

public static void main(String[] args) {
        Map map = new HashMap<>();
        test("null", 101, null);
    }

    public static void test(String name, Integer age, Map extraInfo) {
        Preconditions.checkNotNull(name, "name must be given");
        Preconditions.checkArgument(age >= 18, "未成年人不能观看");

        Map defaultExtraInfo = Maps.newHashMap();
        defaultExtraInfo.put("name", "wudy");
        extraInfo = Optional.fromNullable(extraInfo).or(defaultExtraInfo); // java API方式: Optional.ofNullable(extraInfo).orElse(defaultExtraInfo);

        for (Map.Entry entry : extraInfo.entrySet()){
            System.out.println(entry.getKey() + ":" + entry.getValue());  // name:wudy
        }
    }
  • 11.Guava RateLimiter
    参考文章: https://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&mid=2247546330&idx=2&sn=864bf29bb10748f34be380cfcdd63f83&chksm=eb50b0ecdc2739fa9fd4d2241d74b3f516273944d64ef22d46e20bce0b877660499b7a827430&mpshare=1&scene=23&srcid=1014KCFaEZRo7IYKNhPsA5P0&sharer_sharetime=1634185620678&sharer_shareid=f770d25bc57f1c2f9159f85750f854dc#rd

    1. Guava骚操作
      参考文章:https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&mid=2247572229&idx=1&sn=e82470244be0bfa059a7efd34a9f3772&chksm=fa4ba4b4cd3c2da2819c28ddaa37493e8aa3ebf5733e3cdb03269f4e017ead8210b222c5b546&mpshare=1&scene=23&srcid=0509HUFL13l1c6FKdSFePdnv&sharer_sharetime=1683621223963&sharer_shareid=7fec9c1809ccb850bfdebba7d4f7a81e#rd

你可能感兴趣的:(Google Guava)