Java高效编程类库-Guava入门与实践


Guava的类特别多,就将常用的进行展开记录,以后需要用到了再补充

Guava简介

Guava工程包含了若干个被Google的Java项目广泛依赖的核心库,例如:集合、缓存、原生类型支持、并发库、通用注解、字符串处理、I/0等等

引入依赖

	 <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>27.1-jre</version>
    </dependency>

对null处理 :Optional类

Optional 类是一个可以为null的容器对象
Optional 类的引入很好的解决空指针异常

JDK8中,将Optional类引入到了Java 8的类库,所以可以直接使用JDK的Optional类

创建Optional对象的三种方式

        //创建空的Optional对象
        Optional.empty();

        //使用非null值创建Optional对象
        Optional.of("zhangsan");

        //使用任意值创建Optional对象
        Optional<Object> optional = Optional.ofNullable("zhangsan");

常用方法:

  • 判断是否引用缺失(null)
		/**
         * 判断是否引用缺失(是否为空)
         * 不建议使用
         */
        optional.isPresent();
  • 如果引用存在(非nulll),则进行系列操作
		/**
         * 如果引用存在,即不为null,进行操作(如打印)
         * 类似的有map。flatmap,filter
         */
        optional.ifPresent(System.out::println);
  • 引用缺失时的三种操作
		optional.orElse("引用缺失");//缺失修改值为某值


        optional.orElseGet(() -> {//缺失时直接进行相应操作(如返回提示)
            return "自定义引用缺失";
        });


        optional.orElseThrow(() -> {//缺失时可以抛出异常
            throw new RuntimeException("引用缺失异常");
        });
  • 实际应用实践

创建一个方法通过流打印集合内容

	public static void stream(List<String> list) {
        //如果list为空,会抛出异常
        list.stream().forEach(System.out::println);
    }

如果list为空,则会抛出异常,stream初始化失败
使用Optional进行优化:

	public static void stream(List<String> list) {
        //如果list不为空,初始化流,如果为空,初始化一个空的流
        Optional.ofNullable(list)
                .map(List::stream)
                .orElseGet(Stream::empty)
                .forEach(System.out::println);
    }
  1. 首先通过 Optional.ofNullable(list)创建一个Optional对象
  2. 如果Optional对象引用存在,则执行map中的list.stream()方法
  3. 如果Optional对象引用缺失,则执行 Stream.empty()方法创建一个空的对象
  4. 最后再打印输出

不可变集合 :Immutable*类

不可变对象的优点:

  • 当对象被不可信的库调用时,是安全的
  • 不可变对象在多线程环境下安全
  • 不可变集合不需要考虑变化,可以节省时间和空间
  • 不可变对象常作为常量来安全使用

Immutabl*是一系列的不可变集合,包括了很多很多的类,使用起来其实大同小异,一下就以ImmutableSet说明下他的创建
在这里插入图片描述

创建不可变对象的三种方式(以ImmutableSet为例)

		List<Integer>list = new ArrayList<Integer>(){
            {add(1);}
            {add(2);}
            {add(3);}
        };
		//通过已存在集合创建
        ImmutableSet.copyOf(list);

        //通过初始值直接创建不可变集合
        ImmutableSet.of(1, 2, 3, 4, 5);

        //以builder方式创建
        ImmutableSet immutableSet = ImmutableSet.builder()
                .add(1)
                .addAll(Sets.newHashSet(2, 3, 4))
                .add(5)
                .build();

构建好的Immutable*的对象不具有添加和删除的接口
在这里插入图片描述

新的集合类型 Multiset接口

类似的还有和Multimap接口,一下以Multiset为例

Multiset是一种介于Set和List直接的一种数据结构,两种角度理解Multiset

  • 没有元素顺序限制的ArrayList
    • add(E):添加单个元素
    • iterator():返回一个迭代器
    • size():返回所有元素的总个数(包括重复的)
  • Map<E,Integer>,键为元素,值为计数
    • count(Object):返回给的元素的计数
    • entrySet():相当于Map中的entrySet
    • elementSet():相当于Map中的KeySet

接口的五种实现类:

  • HashMultiset
  • TreeMultiset
  • LinkedHashSet
  • ConcurrentHashMultiset
  • mmutableMultiset

业务中的实践:

实现字符统计的功能

/**
 * 〈使用Mutiset统计古诗文字出现频率〉
 *
 * @author Chkl
 * @create 2020/4/21
 * @since 1.0.0
 */
public class MultisetTest {

    private static final String text =
            "《山坡羊·潼关怀古》\n" +
                    "峰峦如聚,波涛如怒,山河表里潼关路。 \n" +
                    "望西都,意踌躇。\n" +
                    "伤心秦汉经行处,宫阙万间都做了土。 \n" +
                    "兴,百姓苦。亡,百姓苦。";

    @Test
    public void handle(){
        //创建Multiset
        Multiset<Character> multiset = HashMultiset.create();

        //stirng to char
        char[] chars = text.toCharArray();

        //遍历数组,加入到multiset
        Chars.asList(chars)
                .stream()
                .forEach(charitem->{
                    multiset.add(charitem);
                });

        System.out.println(multiset.size());
        for (Character c : multiset.elementSet()){
            System.out.println(c+" "+multiset.count(c));
        }
    }
}

常用工具集 :Sets、Lists类

Sets工具类常用方法: 并集、交集、差集、分解集合中所有的子集、求两个集合的笛卡尔积

Lists工具类常用方法: 反转、拆分

演示实践:

初始化两个set

    private static final Set set1 =
            Sets.newHashSet(1, 2, 3, 4);
    private static final Set set2 =
            Sets.newHashSet(4, 5, 6);
  • 求并集

    @Test
    public void union() {
        Set<Integer> set = Sets.union(set1, set2);
        System.out.println(set);
    }
  • 求交集
	@Test
    public void intersection() {
        Set<Integer> set = Sets.intersection(set1, set2);
        System.out.println(set);
    }
  • 求差集
    元素属于a但不属于b
	@Test
    public void difference() {
        Set<Integer> set = Sets.difference(set1, set2);
        System.out.println(set);
    }
  • 求相对差集
    元素属于a但不属于b 或元素属于b但不属于a
	@Test
    public void symmetricDifference() {
        Set<Integer> set = Sets.symmetricDifference(set1, set2);
        System.out.println(set);
    }
  • 拆解集合(求所有子集)
	@Test
    public void powerSet() {
        Set<Set<Integer>> set = Sets.powerSet(set1);
        System.out.println(JSON.toJSONString(set));
    }
  • 求笛卡尔积
 	@Test
    public void cartesianProduct() {
        Set<List<Integer>> set = Sets.cartesianProduct(set1, set2);
        System.out.println(JSON.toJSONString(set));
    }

初始化一个List

private static final List<Integer> list =
            Lists.newArrayList(1, 2, 3, 4, 5, 6, 7);
  • 按指定长度拆分
 	@Test
    public void partition() {
        List<List<Integer>> partition = Lists.partition(list, 3);
        System.out.println(JSON.toJSONString(partition));
    }
  • 反转集合
	@Test
    public void reverse() {
        List<Integer> reverse = Lists.reverse(list);
        System.out.println(JSON.toJSONString(reverse));
    }

IO操作: Files类

对字节流和字符流操作的封装

  • ByteStreams:提供对InputStream和OutputStream针对字节流的操作
  • CharStreams:提供Reader和Writer针对字符流的操作

针对源(Source)和汇(Sink)的抽象

  • 源(可读的):ByteSource/CharSource
  • 汇(可写的):ByteSink/CharSink

Files中封装了很多好用的方法,这里主要记录一下源与汇的使用

实践案例:
通过源与汇实现文件拷贝,源与汇是比较高级的封装,直接使用不需要对输入输出流进行创建和关闭

	 /**
     * 通过源与汇实现文件拷贝
     */
    @Test
    public void copyFile() throws IOException {
        /**
         * 创建对应的Source和Sink
         */
        CharSource charSource = Files.asCharSource(
                new File("lib/FileCopy.java"), Charsets.UTF_8);
        CharSink charSink = Files.asCharSink(
                new File("outTest/out.txt"), Charsets.UTF_8);

        /**
         * 拷贝,不需要创建连接和关闭连接
         */
        charSource.copyTo(charSink);
        
    }

更多的方法在具体使用时查Api吧 ,源与汇还是挺好用的

最后

Guava用起来非常强大,方法也非常多,找到一个算是目录的网站,可以去系统的看一看Api 直达

猜你喜欢

转载自blog.csdn.net/qq_41170102/article/details/105663618
今日推荐