首页 > 其他分享 >Guava常用工具类总结

Guava常用工具类总结

时间:2022-08-21 12:24:50浏览次数:79  
标签:总结 String list System println Guava 常用工具 public out

Guava常用工具类总结

-"我想写得更优雅,可是没人告诉我怎么写得更优雅" 
-"Null的含糊语义让人很不舒服。Null很少可以明确地表示某种语义,例如,Map.get(key)返回Null时,可能表示map中的值是null,亦或map中没有key对应的值。Null可以表示失败、成功或几乎任何情况。使用Null以外的特定值,会让你的逻辑描述变得更清晰。"
此文档只是Guava最常用工具介绍,guava存在更多本文档没有介绍的api

一丶Optional

Optional类是Java8为了解决null值判断问题,借鉴google guava类库的Optional类而引入的一个同名Optional类,使用Optional类可以避免显式的null值判断(null的防御性检查),避免null导致的NPE(NullPointerException)。

这里讲的optional 也是指jdk中的optional,其实二者类似,
但是编码使用gauva的optional,阿里巴巴编程规范会提醒换成jdk自带的optional

1.不要用isPressent判断一个对象是否为空

这种用法不但没有减少null的防御性检查,而且增加了Optional包装的过程,违背了Optional设计的初衷,因此开发中要避免这种糟糕的使用

public enum TestEnum {
    /***
     * 编号和对应的名称
     */
    CuzInHongAn("0929", "红安一中"),
    CuzInCupk("2017015600", "克电"),
    CuzInChengdu("80309525", "招银"),
    ;
    @Getter
    private String code;
    @Getter
    private String name;

    TestEnum(String code, String name) {
        this.code = code;
        this.name = name;
    }

    public static String getNameByCod(String code) {
        Optional<String> nameOfCode = Arrays.stream(TestEnum.values())
                .filter(item -> StringUtils.equals(item.code, code))
                .map(TestEnum::getName)
                .findFirst();
        //不要这样使用optional 这样optional的意义:优雅的处理空指针 就不存在了
        if (nameOfCode.isPresent()) {
            throw new RuntimeException("不存在");
        }
        // 请使用orElseThrow 和orElse
        return nameOfCode.orElseThrow(() -> new RuntimeException("不存在"));
    }
}

2.考虑让方法返回optional

《Effective Java》中对方法返回Optional的一些观点

  • 容器(包括,集合,映射,数组,stream,optional)都不应该包装在Optional进行返回,返回空的容器能让客户端免于处理一个Optional
  • 如果无法返回结果,且没有返回结果客户端必须进行特殊的处理,那么就应该声明返回optional
  • 返回optional并不是一个不需要成本的操作,无论返回空,还是非空,使用optional作为返回值的方法都是需要初始化的,所以optional在看重性能的情况下使用不当是一种性能的浪费
  • 永远不要返回基本类型对于包装类型的Optional,这需要进行基本类型->包装类型->optional的三层包装,可以使用OptionalInt,optionallong等

二丶PreConditions前置条件检查

前置条件:让方法调用的前置条件判断更简单。api比较见名知意,根据参数分为三种:

  • 没有额外参数:抛出的异常中没有错误消息;
  • 有一个Object对象作为额外参数:抛出的异常使用Object.toString() 作为错误消息;
  • 有一个String对象作为额外参数,并且有一组任意数量的附加Object对象:这个变种处理异常消息的方式有点类似printf,但考虑GWT的兼容性和效率,只支持%s指示符。

例子:

  • test1 缺点:if看起来臃肿,优点:可用抛出我们系统的自定义异常便于前端反馈
  • test2 优点:简单直接,缺点:抛出的都是jdk中的异常,通一异常处理可能无法返回正确提示的通一结果集给前端

我们可用写一个带异常Class的工具类或者直接代理guava中的Predition 加一层try catch 使我其抛出我们系统的自定义异常

    public static String test1(Integer index, List<String>list){
        if (Objects.isNull(index)){
            throw new RuntimeException("index不可以为空");
        }
        if (CollectionUtils.isEmpty(list)){
            throw new RuntimeException("list不可以为空");
        }
        if (index<0||index>=list.size()){
            throw new RuntimeException(String.format("越界无法获取,下标%S",index));
        }
        return list.get(index);
    }

    public static String test2(Integer index, List<String>list){
        Preconditions.checkNotNull(index,"index不可以为空");
        Preconditions.checkNotNull(list,"list不可以为空");
        Preconditions.checkElementIndex(index,list.size(),String.format("越界无法获取,下标%S",index));
        Preconditions.checkArgument(index >= 0&&index<list.size(),"越界无法获取,下标%S",index);
        return list.get(index);
    }

三丶ComparisonChain和Ordering

想象一个场景,人先根据age排序后根据height排序

1.实现comparable

1.1写法1:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class People implements Comparable<People> {
    private Integer age;
    private Integer height;
    @Override
    public int compareTo(People o) {
        if (!Objects.equals(this.age, o.age)) {
            return this.age - o.age;
        }else {
            return this.height - o.height;
        }
    }
    public static void main(String[] args) {
        People p1 = People.builder().build();
        People p2 = People.builder().build();
        List<People> list = Arrays.asList(p1, p2);
        Collections.sort(list);
        System.out.println(list);
    }
}

//你或许会写得更高级一点 如下
    @Override
    public int compareTo(People o) {
        int ageCompare = Ints.compare(this.age, o.age);
        if (ageCompare==0){
            return Ints.compare(this.height, o.height);
        }else {
            return ageCompare;
        }
    }

缺点:

  • 写法繁琐
  • 忽略了空指针, return this.age - o.age; 这一句存在空指针的情况,对null进行拆箱直接NPE
  • 维护复杂,再加一个存款,加逻辑复杂

1.2写法2:

@Override
public int compareTo(People o) {
    int thisAge = Optional.ofNullable(this.age).orElse(Integer.MAX_VALUE);
    int thisHeight = Optional.ofNullable(this.height).orElse(Integer.MAX_VALUE);
    int oAge = Optional.ofNullable(o.age).orElse(Integer.MAX_VALUE);
    int oHeight = Optional.ofNullable(o.height).orElse(Integer.MAX_VALUE);
    if (thisAge!=oAge){
        return thisAge-oAge;
    }else {
        return thisHeight - oHeight;
    }
}

解决了空指针,还实现了Null指在最前或者最后

缺点:

  • 繁琐
  • 语法化不明显,看懂代码太累了
  • 维护复杂,再加一个存款,加逻辑复杂

1.2写法3:

   return ComparisonChain.start()
                .compare(this.age, o.age, Ordering.natural().nullsFirst())
                .compare(this.height, o.height,Ordering.natural().nullsFirst())
       //让True在最前面,但是无法处理空的BoolBean
                .compareTrueFirst(Optional.ofNullable(this.sex).orElse(false),
                        Optional.ofNullable(o.sex).orElse(false))
                .result();

//想一下这个需求你自己写,代码会多么繁琐

优点:

  • 优雅的处理空指针,传入比较器 Ordering.natural().nullsFirst() 让null在最前面
  • 链式调用yyds
  • 语义化明显:先比较age 后比较 height吗,null在最前面
  • 更易于维护,只需要加一行

2.使用Comparator

典型的策略模式,将算法和业务分离开

大概基础的写法和上述的1.1 1.2差不多,不做过多赘述,直接上干货

2.1请使用Ordering

方法 描述
natural() 对可排序类型做自然排序,如数字按大小,日期按先后排序
usingToString() 按对象的字符串形式做字典排序[lexicographical ordering]
from(Comparator) 把给定的Comparator转化为排序器
reverse() 获取语义相反的排序器
nullsFirst() 使用当前排序器,但额外把null值排到最前面。
nullsLast() 使用当前排序器,但额外把null值排到最后面。
compound(Comparator) 合成另一个比较器,以处理当前排序器中的相等情况。
  public static void main(String[] args) {
        People p1 = People.builder().build();
        People p2 = People.builder().age(1000).height(2).build();
        List<People> list = Arrays.asList(p1, p2,null);
        Comparator<People> ageComparator = (o1, o2) -> ComparisonChain.start().compare(o1.age, o2.age, Ordering.natural().nullsFirst()).result();
        Comparator<People> heightComparator = (o1, o2) -> ComparisonChain.start().compare(o1.height, o2.height, Ordering.natural().nullsFirst()).result();
        Ordering<People> compound = Ordering.natural().nullsFirst().compound(ageComparator).compound(heightComparator);
        list.sort(compound);
        System.out.println("源list 排序之后");
        System.out.println(list);
        //深拷贝返回一个排序后的people
        List<People> peopleList = compound.sortedCopy(list);
        System.out.println("深拷贝一个list结果");
        System.out.println(peopleList);

        Ordering<People> withDefault = compound.onResultOf(new Function<People, People>() {
            @Override
            public @Nullable People apply(@Nullable People input) {
                return Optional.ofNullable(input).orElse(new People(21, 175, false));
            }
        });
        Collections.shuffle(peopleList);
        System.out.println("打乱深拷贝的list");
        System.out.println("深拷贝一个list结果");
        System.out.println(peopleList);
        System.out.println("源list");
        System.out.println(list);
        System.out.println("使用带默认值的排序结果");
        peopleList.sort(withDefault);
        System.out.println("深拷贝一个list结果");
        System.out.println(peopleList);
        //这句会显示废弃 很巧妙
//        Ordering.from(Ordering.natural())
    }

四丶Throwables

Throwables 可用简化异常和错误的传播与检查,什么叫错误的传播——不捕获异常向上抛出,什么是异常的检查——多个catch,catch不同类型的异常进行不同的处理

//好用,但是差点意思
方法 含义
Throwables.throwIfInstanceOf(e, FileNotFoundException.class); 如果异常属于第二个参数的类型,那么抛出
Throwables.throwIfUnchecked(e); 如果这个异常是非Unchecked Exception(即运行时异常)那么抛出
Throwable getRootCause(Throwable
List getCausalChain(Throwable
String getStackTraceAsString(Throwable

例子:比较test1 和test2 使用Throwables似乎能让代码更加简洁

public class ThrowablesLearn {


    public static Integer doSomeThing(int num) throws FileNotFoundException, SQLException {
        //想象这是你的封装的方法,不同的情况你需要抛出不同的异常
        if (num % 2 == 0) {
            throw new FileNotFoundException("FileNotFoundException");
        } else if (num % 3 == 0) {
            throw new RuntimeException("RuntimeException");
        } else if (num % 5 == 0) {
            throw new SQLException("SQLException");
        }
        List<String> integers = Arrays.asList("1", "2", "3", "4", "5", "6", "7aa", "8", "9");
        //输入7这里抛出NumberFormatException 因为 7aa 不能转换为数字
        return Integer.valueOf(integers.get(num - 1));
    }

    public static void test1() throws FileNotFoundException {
        //想象这是你业务代码 调用上面方法
        try {
            //这里输入不是数字也会抛出异常
            int num = new Scanner(System.in).nextInt();
            System.out.println(doSomeThing(num));
            // 你只想 抛出FileNotFoundException
            // ,SQLExceptionn包装成runtimeException异常
            // 其他的异常你打印日志就可
        } catch (FileNotFoundException e) {
            throw e;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } catch (Exception e) {
            System.out.println("操作失败 失败原因");
            e.printStackTrace();
        }
    }

    public static void test2() throws FileNotFoundException {
        //想象这是你业务代码 调用上面方法
        try {
            //这里输入不是数字也会抛出异常
            int num = new Scanner(System.in).nextInt();
            System.out.println(doSomeThing(num));
        } catch (Exception e) {
            //你只想 抛出FileNotFoundException SQLException,其他的异常你打印日志就可
            Throwables.throwIfInstanceOf(e, FileNotFoundException.class);
            Throwables.throwIfUnchecked(e);
            System.out.println("操作失败 失败原因");
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws FileNotFoundException {
        test2();
        System.out.println("testEnd");
    }
}

五丶不可变集合

  • 使用场景:

  • 如定义一系列状态比如吃饭,睡觉,过马路,需要根据这个状态判断是否可以玩手机,可以在类中定义集合包装这个三个状态,如果当前状态属于三个之一那么不可以玩手机,你可以使用基本的hashset,但是hashset的元素可以被更改,导致可能方法的判断和原本的语义出现出入

  • 优点

    • 当对象被不可信的库调用时,不可变形式是安全的;
    • 不可变对象被多个线程调用时,不存在竞态条件问题
    • 不可变集合不需要考虑变化,因此可以节省时间和空间。所有不可变的集合都比它们的可变形式有更好的内存利用率(分析和测试细节);
    • 不可变对象因为有固定不变,可以作为常量来安全使用。
public class ImmutableLearn {


    private final Set<String>statusCannotPlayWithPhone;

    public ImmutableLearn(Set<String> statusCannotPlayWithPhone) {
        this.statusCannotPlayWithPhone = statusCannotPlayWithPhone;
    }
    public boolean canPlayPhoneOrNot(String status){
        return !statusCannotPlayWithPhone.contains(status);
    }

    public void showWhyShouldUseImmutable(){
        ImmutableLearn immutableLearn = new ImmutableLearn(Sets.newHashSet("sleep", "eat", "crossTheStreet"));
        System.out.println(immutableLearn.canPlayPhoneOrNot("sleep"));
        immutableLearn.statusCannotPlayWithPhone.remove("sleep");
        System.out.println(immutableLearn.canPlayPhoneOrNot("sleep"));

        ImmutableLearn immutableLearn1 = new ImmutableLearn(ImmutableSet.copyOf(Lists.newArrayList("sleep", "eat", "crossTheStreet")));
        System.out.println(immutableLearn.canPlayPhoneOrNot("sleep"));
        immutableLearn.statusCannotPlayWithPhone.remove("sleep");
        System.out.println(immutableLearn.canPlayPhoneOrNot("sleep"));
    }
    
    public static void main(String[] args) {
        //创建不可变集合的三种繁琐
        ImmutableSet<Integer> set1 = ImmutableSet.of(1);
        ImmutableSet<Integer> set2 = ImmutableSet.copyOf(Lists.newArrayList(1,2,3));
        Set<Object> set3 = ImmutableSet.builder()
                .add(1)
                .addAll(set2)
                .addAll(set1)
                .add(10)
                .build();
        System.out.println(set1);
        System.out.println(set2);
        System.out.println(set3);
        //不允许操作
        set3.add(1);
        set3.remove(1);
    }
}

六丶新集合类型

1.Multiset

1.1可以用两种方式看待Multiset:

  • 没有元素顺序限制的ArrayList
    • 当把Multiset看成普通的Collection时,它表现得就像无序的ArrayList:
      • add(E)添加单个给定元素
      • iterator()返回一个迭代器,包含Multiset的所有元素(包括重复的元素)
      • size()返回所有元素的总个数(包括重复的元素)
  • Map<E, Integer>,键为元素,值为计数
    • Multiset看作Map<E, Integer>时,它也提供了符合性能期望的查询操作:
      • count(Object)返回给定元素的计数。HashMultiset.count的复杂度为O(1),TreeMultiset.count的复杂度为O(log n)。
      • entrySet()返回Set<Multiset.Entry>,和Map的entrySet类似。
      • elementSet()返回所有不重复元素的Set,和Map的keySet()类似。
      • 所有Multiset实现的内存消耗随着不重复元素的个数线性增长。

1.2使用Multiset例子

1.统计一个list中单词出现的次数

public class MultiSetLearn {

    /****
     * 刚毕业我会这么写
     * @param list
     * @return
     */
    public static Map<String, Integer> statisticsWordCount1(List<String> list) {
        Map<String, Integer> countMap = new HashMap<>();
        if (list == null || list.size() == 0) {
            return countMap;
        }
        for (String s : list) {
            int nowCount = countMap.getOrDefault(s, 0);
            countMap.put(s, nowCount + 1);
        }
        return countMap;
    }

    /**
     * 学了java 8新特性我会这么写
     *
     * @param list
     * @return
     */
    public static Map<String, Integer> statisticsWordCount2(List<String> list) {
        list = Optional.ofNullable(list).orElse(Collections.emptyList());
        return list.stream()
                .collect(Collectors.groupingBy(t -> t,
                        Collectors.reducing(0, num -> 1, Integer::sum)));

    }

    /**
     * 学了guava api
     *
     * @param list
     * @return
     */
    public static Map<String, Integer> statisticsWordCount3(List<String> list) {
        list = Optional.ofNullable(list).orElse(Collections.emptyList());
        HashMultiset<String> multiset = HashMultiset.create(list);
        //可以直接返回HashMultiset 那这个方法可以更加简单
        //但是对不熟悉的guava的同事的有点痛苦
        System.out.println(multiset);
        return multiset.stream()
                .collect(Collectors.toMap(item -> item, multiset::count, BinaryOperator.maxBy(Ordering.natural())));
    }

    public static void main(String[] args) {
        Map<String, Integer> map = statisticsWordCount3(Arrays.asList("a", "b", "a", "c"));
        map.forEach((k, v) -> System.out.println(k + "-" + v));
    }
}

1.3.SortedMultiset

//就这?

Multiset 接口的变种,它支持高效地获取指定范围的子集。

public class SortMultiSetLearn {

    /**
     * 在不改变源money 元素的情况下 统计介于min和max间的钱
     * money中的null 视为0
     */
    public static List<Float> findMoneyBetween1(float min, float max, List<Float> money) {
        money = Optional.ofNullable(money).orElse(Collections.emptyList());
        return money.stream().map(item -> Optional.ofNullable(item).orElse(0F))
                .filter(item -> item > min && item < max)
                .collect(Collectors.toList());
    }

    /**
     * 在不改变源money 元素的情况下 统计介于min和max间的钱
     * money中的null 视为0
     */
    public static List<Float> findMoneyBetween2(float min, float max, List<Float> money) {
        money = Optional.ofNullable(money).orElse(Collections.emptyList());
        TreeMultiset<Float> treeMultiset = TreeMultiset.create(Ordering.<Float>natural().onResultOf(f1 -> Optional.ofNullable(f1).orElse(0F)));
        treeMultiset.addAll(money);
        return Lists.newLinkedList(treeMultiset.subMultiset(min, BoundType.CLOSED, max, BoundType.CLOSED));
    }
}

2.Multimap

Guava的 Multimap可以很容易地把一个键映射到多个值。换句话说,Multimap是把键映射到任意多个值的一般方式

2.1合并两个map

public static Map<String, Collection<Integer>> mergeMap1(Map<String, Integer> map1, Map<String, Integer> map2) {
    map1 = Optional.ofNullable(map1).orElse(Collections.emptyMap());
    map2 = Optional.ofNullable(map2).orElse(Collections.emptyMap());
    Set<String> allKey = Stream.of(map1.keySet(), map2.keySet()).flatMap(Collection::stream).collect(Collectors.toSet());
    Map<String, Collection<Integer>> resMap = Maps.newHashMap();
    for (String key : allKey) {
        Integer integer1 = map1.get(key);
        Integer integer2 = map2.get(key);
        Set<Integer> tempSet = Sets.newHashSet();
        if (Objects.nonNull(integer1)) {
            tempSet.add(integer1);
        }
        if (Objects.nonNull(integer2)) {
            tempSet.add(integer2);
        }
        resMap.put(key, tempSet);
    }
    return resMap;
}

public static Map<String, Collection<Integer>> mergeMap2(Map<String, Integer> map1, Map<String, Integer> map2) {
    map1 = Optional.ofNullable(map1).orElse(Collections.emptyMap());
    map2 = Optional.ofNullable(map2).orElse(Collections.emptyMap());
    Multimap<String, Integer> multimap = HashMultimap.create();
    map1.forEach(multimap::put);
    map2.forEach(multimap::put);
    return multimap.asMap();
}

3.BiMap

BiMap是特殊的Map:

  • 可以用 inverse()反转BiMap<K, V>的键值映射
  • 保证值是唯一的,因此 values()返回Set而不是普通的Collection
  • 在BiMap中,如果你想把键映射到已经存在的值,会抛出IllegalArgumentException异常。如果对特定值,你想要强制替换它的键,请使用 BiMap.forcePut(key, value)
public class BiMapLearn {

    public static void main(String[] args) {
        //想象这是用户id 和用户名对应map
        //你需要根据id查询用户名。根据用户名查询id(用户名同样不可以重复)
        HashBiMap<String, String> userNameAndIdMap = HashBiMap.create();
        userNameAndIdMap.put("2017015600","陈兴cupk");
        userNameAndIdMap.put("80309525","陈兴cmbnk");
        // 重复value 会抛出异常ava.lang.IllegalArgumentException:
        // value already present: 陈兴cmbnk
//        userNameAndIdMap.put("309525","陈兴cmbnk");
        //forcePut 可以强制替换 key -value 组合
//        userNameAndIdMap.forcePut("309525","陈兴cmbnk");
        System.out.println(userNameAndIdMap.get("2017015600"));
        System.out.println(userNameAndIdMap.inverse().get("陈兴cmbnk"));
        System.out.println(userNameAndIdMap.get("80309525"));
        //set类型的key value
        Set<String> strings = userNameAndIdMap.keySet();
        Set<String> values = userNameAndIdMap.values();
    }
}

4.Table

  • 使用场景:当你需要多个字段作为key时,你可能为这个key编写一个类,重写equals和hashMap。或者使用形同Map<FirstName, Map<LastName, Person>>的map结构,前者编码繁琐,后者使用不友好(第一个get后判空,后才能左第二次get)

  • Guava为此提供了新集合类型Table,它有两个支持所有类型的键:”行”和”列”。Table提供多种视图,以便你从各种角度使用它:

    • rowMap():用Map<R, Map<C, V>>表现Table<R, C, V>。同样的, rowKeySet()返回”行”的集合Set
    • row(r) :用Map<C, V>返回给定”行”的所有列,对这个map进行的写操作也将写入Table中。
    • 类似的列访问方法:columnMap()columnKeySet()column(c)。(基于列的访问会比基于的行访问稍微低效点)
    • cellSet():用元素类型为Table.Cell的Set表现Table<R, C, V>。Cell类似于Map.Entry,但它是用行和列两个键区分的。
  • 使用示例

    public class TableLearn {
    
        public static void main(String[] args) {
            System.out.println(getNameByAgeAndNo1(17, "201715600"));
            System.out.println(getNameByAgeAndNo2(17, "201715600"));
        }
    
    	//根据年龄和编号 获取名字,编写KeyOfAgeAndNo 重写equals hashcode
        public static String getNameByAgeAndNo1(int age,String no){
            HashMap<KeyOfAgeAndNo, String> memory = Maps.newHashMap();
            memory.put(KeyOfAgeAndNo.of(17,"201715600"),"大一的陈兴");
            memory.put(KeyOfAgeAndNo.of(14,"0929"),"高一的陈兴");
            memory.put(KeyOfAgeAndNo.of(20,"80303697"),"实习的陈兴");
    
            return Optional.ofNullable(memory.get(KeyOfAgeAndNo.of(age, no)))
                    .orElseThrow(() -> new RuntimeException("查无此人"));
        }
    	//编写KeyOfAgeAndNo 重写equals hashcode
        static class KeyOfAgeAndNo{
            Integer age;
            String no;
            static KeyOfAgeAndNo of( Integer age,String no){
                KeyOfAgeAndNo res = new KeyOfAgeAndNo();
                res.age=age;
                res.no=no;
                return res;
            }
            @Override
            public boolean equals(Object o) {
                if (this == o) return true;
                if (!(o instanceof KeyOfAgeAndNo)) return false;
                KeyOfAgeAndNo that = (KeyOfAgeAndNo) o;
                return Objects.equals(age, that.age) &&
                        Objects.equals(no, that.no);
            }
    
            @Override
            public int hashCode() {
                return Objects.hash(age, no);
            }
        }
    	//使用table 
        public static String getNameByAgeAndNo2(int age,String no){
            HashBasedTable<Integer ,String,String>table=HashBasedTable.create();
            table.put(17,"201715600","大一的陈兴");
            table.put(14,"0929","高一的陈兴");
            table.put(20,"80303697","实习的陈兴");
            return Optional.ofNullable(table.get(age, no))
                    .orElseThrow(() -> new RuntimeException("查无此人"));
        }
    }
    

5.ClassToInstanceMap

  • 使用场景,类型指向实例,使用普通map需要

  • 示例

    getInstanceByClass1需要进行强转因为map get方法返回object类型,不能限制key的类型
    getInstanceByClass2则没有这种需要 且可以限定key的类型
    
    
    public class ClassToInstanceMapLearn {
    //静态内部类实现单例 和ClassToInstanceMap 使用没有必要关系
        private static class SingletonHolder {
            private static final ClassToInstanceMapLearn INSTANCE;
    
            static {
                INSTANCE = new ClassToInstanceMapLearn();
            }
        }
    
        private ClassToInstanceMapLearn() {
            System.out.println("ClassToInstanceMapLearn Constructor");
        }
    
        public static ClassToInstanceMapLearn newInstance() {
            return SingletonHolder.INSTANCE;
        }
    
        private static final Map<Class<?>, ? super ClassToInstanceMapLearn> Memory1 = new HashMap<>();
    
        static {
            Memory1.put(ClassToInstanceMapLearn.class, ClassToInstanceMapLearn.newInstance());
            //加入从 简单工场拿SingletonHolder实例 强转化 将抛出异常
            Memory1.put(SingletonHolder.class, ClassToInstanceMapLearn.newInstance());
        }
    
        public static <T extends ClassToInstanceMapLearn> T getInstanceByClass1(Class<T> clazz) {
            //需要强转需要去判断 是否是clazz的实例 错误写法
            return (T) Optional.ofNullable(Memory1.get(clazz))
                    .orElseThrow(() -> new RuntimeException("不存在"));
        }
    
        private static final ClassToInstanceMap<? super ClassToInstanceMapLearn> Memory2 = MutableClassToInstanceMap.create();
    
        static {
            Memory2.putInstance(ClassToInstanceMapLearn.class, ClassToInstanceMapLearn.newInstance());
            //无法加入
    //        Memory2.put(SingletonHolder.class, ClassToInstanceMapLearn.newInstance());
        }
    
        public static <T extends ClassToInstanceMapLearn> T getInstanceByClass2(Class<T> clazz) {
            //不需要强壮
            return Optional.ofNullable(Memory2.getInstance(clazz))
                    .orElseThrow(() -> new RuntimeException("不存在"));
        }
    
    
        public static void main(String[] args) {
            System.out.println(getInstanceByClass1(ClassToInstanceMapLearn.class));
             System.out.println(getInstanceByClass2(ClassToInstanceMapLearn.class));
        }
    }
    

七丶集合工具类

  • guava 中的集合工具常常以集合名称加s出现

    • Collections2 因为java存在Collections guava加了2
    • Lists
    • Maps
    • Sets
    • 等等 上面介绍的新集合类型也存在对应的工具类
  • 这些工具类的共性

    • 都存在静态工厂方法

      • 为什么要使用静态工厂方法,它相比于构造方法(这里的静态工厂方法不是指,设计模式中的工厂模式)

        《Effective Java》第一条 使用静态工厂方法代替构造器,给予了解答

        • 静态工厂方法有名字

          //这一句是什么意思
          BigInteger big1 = new BigInteger(10, 100, new Random(10));
          System.out.println(big1);
          //这一句又是什么意思
          BigInteger big2 = BigInteger.probablePrime(10, new Random(10));
          System.out.println(big2);
          
        • 静态工厂方法,不必每次都生成一个对象

          //虽然下面两句都在放屁,但是前者的屁更臭
          boolean flag = new Random().nextInt() % 2 == 0;
          //每次生成一个新对象
          Boolean b1 = new Boolean(flag);
          //不会生成新对象
          Boolean b2 = Boolean.valueOf(flag);
          
        • 静态工厂方法可以返回任何原返回类型的子类型,如guava中的api

        • 静态工厂的返回对象的类可也随着每次调用而变化,取决于入参类似于简单工厂模式

        • 静态工厂方法返回的对象所属的类可以在,在编写百行该静态工厂方法的类时不存在,如JDBC数据库连接

1.Collections2

  • 过滤

    public static void filterLearn() {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, null);
        Collection<Integer> filter = Collections2.filter(list, Objects::nonNull);
        System.out.println(list);
        System.out.println(filter);
        //返回一个继承了AbstractCollection的集合
        System.out.println(filter.getClass());
    }
    
  • 转换

    public class Collections2Learn {
        private Integer nums;
    
        public Collections2Learn(Integer nums) {
            this.nums = nums;
        }
        
        public static void transformLearn() {
            com.cuzz.miscellaneous.guava.collectionutils.Collections2Learn c1 = new com.cuzz.miscellaneous.guava.collectionutils.Collections2Learn(1);
            com.cuzz.miscellaneous.guava.collectionutils.Collections2Learn c2 = new com.cuzz.miscellaneous.guava.collectionutils.Collections2Learn(2);
            com.cuzz.miscellaneous.guava.collectionutils.Collections2Learn c3 = new com.cuzz.miscellaneous.guava.collectionutils.Collections2Learn(3);
            List<com.cuzz.miscellaneous.guava.collectionutils.Collections2Learn> list = Arrays.asList(c1, c2, c3);
            Collection<Integer> transform = Collections2.transform(list,
                    t -> Optional.ofNullable(t)
                            .orElse(new com.cuzz.miscellaneous.guava.collectionutils.Collections2Learn(0)).nums);
            System.out.println(transform);
            System.out.println(transform.getClass());
        }
    }
    
  • 全排列

    public static void main(String[] args) {
        ArrayList<Integer> list = Lists.newArrayList(1, 2, 3);
        Collection<List<Integer>> lists = Collections2.orderedPermutations(list);
        lists.forEach(System.out::println);
        Collection<List<Integer>> permutations = Collections2.permutations(list);
        System.out.println("====");
        permutations.forEach(System.out::println);
    }
    

2.lists

  • 切割

    //获取一个字符串中的全部字符,返回不可变集合
    ImmutableList<Character> chars = Lists.charactersOf("123");
    System.out.println(chars);
    //按照大小分割list
    ArrayList<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7);
    List<List<Integer>> partitionList = Lists.partition(intList, 2);
    System.out.println(partitionList);
    

2.sets

  • 交集

    HashSet<Integer> set1 = Sets.newHashSet(1, 2, 3);
    HashSet<Integer> set2 = Sets.newHashSet(1, 2, 4,5);
    //返回交集
    Sets.SetView<Integer> intersection = Sets.intersection(set1, set2);
    System.out.println(intersection);
    
  • 差集

    //返回set1中存在 s2中不存在的元素
    System.out.println(Sets.difference(set1, set2));
    System.out.println(Sets.difference(set2, set1));
    
  • 并集

    //返回并集
    Sets.SetView<Integer> union = Sets.union(set1, set2);
    System.out.println(union);
    
  • 过滤

System.out.println(Sets.filter(union, t -> t % 2 == 0));

3.maps

  • uniqueIndex 根据传入的function生成map
ArrayList<Integer> list1 = Lists.newArrayList(1, 2, 3, 4, 6);
//传入function根据function生成map 要求 key 不可重复
ImmutableMap<String, Integer> integerImmutableMap = Maps.uniqueIndex(list1, String::valueOf);
  • 获取两个map的不同
//如果你预计hashMap的大小请使用这个方法
HashMap<String, Integer> map1 = Maps.newHashMapWithExpectedSize(3);
map1.put("1", 1);
map1.put("2", 2);
map1.put("3", 3);
map1.put("4", 3);
map1.put("5", 5);
ArrayList<Integer> list1 = Lists.newArrayList(1, 2, 3, 4, 6);
//传入function根据function生成map 要求 key 不可重复
ImmutableMap<String, Integer> integerImmutableMap = Maps.uniqueIndex(list1, String::valueOf);
MapDifference<String, Integer> difference = Maps.difference(map1, integerImmutableMap);
//左边独有key
Map<String, Integer> mapLeft = difference.entriesOnlyOnLeft();
//右边独有key
Map<String, Integer> mapRight = difference.entriesOnlyOnRight();
//两个map相同key 但是不同value
Map<String, MapDifference.ValueDifference<Integer>> valueDifferenceMap = difference.entriesDiffering();
//左边map的值 有边map的值
System.out.println(valueDifferenceMap.get("4").rightValue());
System.out.println(valueDifferenceMap.get("4").leftValue());
  • 过滤

    //过滤map 中的Entries
    Map<String, Integer> filterEntriesMap = Maps.filterEntries(map1, e -> {
        assert e != null;
        return StringUtils.equals(e.getKey(), String.valueOf(e.getValue()));
    });
    //过滤key
    Map<String, Integer> filterKeysMap = Maps.filterKeys(map1, StringUtils::isNotBlank);
    //过滤value
    Map<String, Integer> filterValuesMap = Maps.filterValues(map1, v -> {
        assert v != null;
        return v % 2 == 0;
    });
    
  • 根据map构造转换器

    HashBiMap<String, Integer> biMapForConverter = HashBiMap.create(integerImmutableMap);
    Converter<String, Integer> converter = Maps.asConverter(biMapForConverter);
    System.out.println(converter.convert("1"));
    Iterable<Integer> convertRes = converter.convertAll(Arrays.asList("1", "2"));
    
  • 转换

    Map<String, String> transformEntriesMap = Maps.transformEntries(map1, (key, value) -> String.valueOf(map1.get(key)));
    //同样还存在
    //        Maps.transformValues()
    

八丶字符串处理

1.连接器[Joiner]

  • 连接任何实现了Iterable结果的类型

    List<Integer> list = Arrays.asList(1, 2, 3, 4, null, 5, null);
    //跳过null
    String str1 = Joiner.on("-").skipNulls().join(list);
    System.out.println(str1);
    //用NNNN代替空
    String str2 = Joiner.on("-").useForNull("NNNN").join(list);
    System.out.println(str2);
    //空指针
    String str3= Joiner.on("-").join(list);
    System.out.println(str3);
    
  • 连接map

    HashMap<String, String> map = Maps.newHashMap();
    map.put("a","1");
    map.put("b","2");
    //每一个k-v连接方式为\n  kv连接方式为->
    String str1 = Joiner.on("\n").withKeyValueSeparator("->").join(map);
    System.out.println(str1);
    
  • 连接实现了Appendable的任何类型

    StringBuilder str3 = Joiner.on("-").appendTo(new StringBuilder(), Arrays.asList("1", "a","2"));
    System.out.println(str3);
    

2.分割器

JDK内建的字符串拆分工具有一些古怪的特性。比如,String.split悄悄丢弃了尾部的分隔符。 问题:”,a,,b,”.split(“,”)返回?

1.“”, “a”, “”, “b”, “”
2.null, “a”, null, “b”, null
3.“a”, null, “b”
4.“a”, “b”
5.以上都不对
正确答案是5:””, “a”, “”, “b”。只有尾部的空字符串被忽略了。 Splitter使用令人放心的、直白的流畅API模式对这些混乱的特性作了完全的掌控。
  • 分割成list

    String str="1-2  -3 - 4- - - ";
    List<String> list1 = Splitter.fixedLength(2).splitToList(str);
    System.out.println(list1);
    List<String> list2 = Splitter.on("-").splitToList(str);
    System.out.println(list2);
    List<String> list3 = Splitter.on("-").trimResults().splitToList(str);
    System.out.println(list3);
    
  • 分割成map

    String str2="1#2-2#3-3#1";
    //每一组entry使用的是-分割 k和v使用的#分割
    Map<String, String> map = Splitter.on("-").withKeyValueSeparator("#").split(str2);
    map.forEach((k,v)-> System.out.println(k+"->"+v));
    
  • 分割成Iterable

    Iterable<String> stringIterable = Splitter.on("-").split(str);
    stringIterable.iterator().forEachRemaining(System.out::println);
    

3.字符匹配器

方法 描述
anyOf(CharSequence) 枚举匹配字符。如CharMatcher.anyOf(“aeiou”)匹配小写英语元音
is(char) 给定单一字符匹配。
[inRange(char, char)](http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/base/CharMatcher.html#inRange(char, char)) 给定字符范围匹配,如CharMatcher.inRange(‘a’, ‘z’)
//删除字符
String str = "/1/2/3/4";
String str1 = CharMatcher.is('/').removeFrom(str);
System.out.println(str1);
String str2 = CharMatcher.anyOf("/1").removeFrom(str);
System.out.println(str2);
String str3 = CharMatcher.noneOf("12/").removeFrom(str);
System.out.println(str3);

String str4 = CharMatcher.inRange('1', '9').removeFrom(str);
System.out.println(str4);
//替换
String str5 = CharMatcher.inRange('1', '9').replaceFrom("a1b2c3", ".");
System.out.println(str5);
//裁剪
String str6 = CharMatcher.inRange('1', '9').trimTrailingFrom("a1b2c3");
System.out.println(str6);
//比对
System.out.println(CharMatcher.inRange('1', '9').matchesAllOf("1b2"));

4.字符集和大小写格式

  • Charsets针对所有Java平台都要保证支持的六种字符集提供了常量引用。尝试使用这些常量,而不是通过名称获取字符集实例。
  • CaseFormat
格式 范例
LOWER_CAMEL lowerCamel
LOWER_HYPHEN lower-hyphen
LOWER_UNDERSCORE lower_underscore
UPPER_CAMEL UpperCamel
UPPER_UNDERSCORE UPPER_UNDERSCORE
CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, "caseFormat")

标签:总结,String,list,System,println,Guava,常用工具,public,out
From: https://www.cnblogs.com/cuzzz/p/16609775.html

相关文章

  • 牛客网笔试输入输出处理方法总结(基于Python3.5)
    牛客网判题系统输入处理牛客网上的输入输出借鉴ACM模式给出,对于习惯了leetcode函数定义形式解题的小伙伴们来说确实比较生疏。为了避免在之后的笔试中再次吃亏,在这里对牛......
  • 多线程.总结
    packageoop.dxcgaoji;importcom.sun.org.apache.xpath.internal.functions.FuncTrue;importjava.util.concurrent.Callable;importjava.util.concurrent.ExecutionExce......
  • 2022年8月21日周六总结(maven install和package的区别未完成)
    最近做了nexus的配置,突然发现maven也很重要,我们平时会在idea用到clear、install、package等,package毫无疑问就是打包jar包了(在maven中定义了),这个打包会把 最近:这里记录......
  • MySQL使用总结
    最近在做一个数据迁移的项目,把mysql数据库中的数据迁移到SqlServer数据库中。在这里记录一下最近遇到的一些问题。一、MySQL中没有top 在MySQL中没有top查询,但是可以使......
  • 软件工程周总结
    在正式编写第一个Python程序前,我们先复习一下什么是命令行模式和Python交互模式。命令行模式在Windows开始菜单选择“命令提示符”,就进入到命令行模式,它的提示符类似C:\>......
  • 算法总结
    1.最近请求次数写一个 RecentCounter 类来计算特定时间范围内最近的请求。请实现RecentCounter类:RecentCounter()初始化计数器,请求数为0。intping(intt)......
  • PHP正则表达式总结(/g,/i,/U等等)
    https://blog.csdn.net/websites/article/details/19199435 PHP正则表达式总结(\nml,\nm,\un,\xn等等)PHP正则表达式语法一个正则表达式就是由普通字符(例如字符a到......
  • HTML5摇一摇以及音频播放问题优化总结
    1.摇一摇不够灵敏、摇动很多次没有响应的问题、原来摇一摇代码是从网络Copy的,活动上线后,发现部分手机摇一摇监测效果不够灵敏,摇动很多次都没有响应,恨不得把手机砸了,于是优......
  • 一周总结
    任务量越来越多啦知识点:Haskell语言是纯函数编程语言Spring启动命令:java-jarxxx.jargit提交本地代码到远程仓库:---暂存区(虚拟工作区)1.gitadd.(跟踪所有新文件......
  • Java跨线程传递数据方式总结
    在微服务调用链中,需要定义一个共享变量,在整个调用链中传递不跨线程的ThreadLocal线程变量,在当前线程任意地方都可共享(可理解为同一线程内部的全局变量)publicc......