深入了解Java 8 新特性:Stream流的实践应用(一)

阅读建议

嗨,伙计!刷到这篇文章咱们就是有缘人,在阅读这篇文章前我有一些建议:

  1. 本篇文章大概一万多字,预计阅读时间长需要10分钟(不要害怕字数过多,其中有一大部分是示例代码,读起来是比较轻松的)。
  2. 本篇文章兼具实战性和理论性,是一篇质量分数较高的技术干货文章,建议收藏起来,方便时常学习与回顾,温故而知新。
  3. 创作不易,免费的点赞、关注,请走上一走,算是对博主一些鼓励,让我更有动力输出更多的干货内容。

前言

        早就打算写一篇文章来梳理一下Java8的新特性Stream流的相关应用,终于得空来完成这件事了。原先以为这块内容应该不会太多,当我梳理完成以后,发现居然有两万多字。当然,在这两万字中,有一部分是示例代码。考虑到一口读完这两字,对于我的读者小伙伴来说,太不友好了,于是乎我打算,把这些内容拆成两部分:

        第一部分,主要是梳理Stream的核心方法;

        第二部分,主要是梳理Collectors类的核心方法;Collectors类是Stream实践应用中非常重要的一个工具类,读完这两篇文章相信肯定能意识到这一点。

Stream是什么

        Java的Stream是Java 8 引入的一个新特性,它提供了一种简洁、优雅的方式来处理集合数据。Stream允许你将集合中的元素进行过滤、映射、排序等操作,并将结果转换为一个新的集合。并且使用Stream,你可以将一个集合转换为一个流,然后对这个流进行各种操作,最后将结果收集到一个新的集合中。这种处理方式非常适合处理大量数据,因为它允许你在内存中一次只处理一个或一小批数据,而不是一次性加载整个数据集到内存中。因此Stream是java8新增特性中一个非常有用且强大的。它的核心特性:

  1. 声明性:Stream的操作以声明的方式进行,这使得代码更易读、易懂。声明性编程强调的是“做什么”,而不是“如何做”,这使得代码更具可维护性和可扩展性。
  2. 可复合:Stream的操作可以链式地进行,即可以将多个操作链接起来运行。这种可复合的特性使得对数据的处理更简洁、更易于理解。
  3. 可并行:Stream可以并行处理数据,这是为了适应多核机器的时代,提高系统CPU、内存的利用率。并行流是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。

这些特性的能够给你带来的好处是:

  1. 提高代码的可读性和可维护性:通过使用声明性和链式操作,可以让代码更加简洁、易于理解和维护。
  2. 提高系统的性能:通过并行流的处理方式,可以充分利用多核CPU的性能,提高系统的处理速度和性能。
  3. 适应大数据时代的需求:随着大数据时代的到来,对大量数据的处理成为一项重要的任务。Stream的并行流处理方式可以满足这种需求,提高数据处理的速度和效率。

Stream的核心方法

Stream#filter

        Stream#filter 方法用于根据指定的条件筛选出 Stream 中的元素。filter 方法接收一个 Predicate 参数,Predicate接口在Java中是一个函数式接口,它只有一个抽象方法,即test(T t),用于接受一个参数并返回一个布尔值。这个接口通常用于定义一个断言(即条件),在编程中可以用于对集合进行过滤或者在函数式编程中作为参数使用

        示例:

        使用Stream#filter()过滤出年龄等于18的学生信息

@Test
public void test() {
    List<Student> list = Arrays.asList(new Student("zhangsan", 18), new Student("lisi", 19), new Student("wangwu", 17));
    List<Student> targetList = list.stream().filter(item -> item.getAge() == 18).collect(Collectors.toList());
    for (Student student : targetList) {
        Assert.isTrue(student.getAge() == 18, "单元测试结果与预期不匹配");
    }
}

Stream#map

        Stream#map方法,它用于将 Stream 中的每个元素映射到另一个元素,Stream#map()方法接受一个Function类型的参数,而Function接口是Java 8引入的函数式接口,主要方法是apply(T t),它接受一个参数并返回一个结果。这个方法可以被看作是一个操作或者函数,它对输入进行某种处理并产生输出。

        示例:

        先使用Stream#filter()过滤出年龄大于18的学生信息,再使用Stream#map()方法把过滤到的结果信息映射成为另外一个类型的

@Test
public void test2() {
    List<Student> list = Arrays.asList(new Student("zhangsan", 18), new Student("lisi", 19), new Student("wangwu", 17));
    List<Person> targetList = list.stream()
            .filter(item -> item.getAge() > 18
            ).map(item -> new Person(item.getName(), item.getAge())).collect(Collectors.toList());
    Assert.notNull(targetList, "单元测试结果与预期不匹配");
}

Stream#mapToInt

        Stream.mapToInt()是Java8中Stream API 的一部分,mapToInt() 方法接受一个函数接口作为参数,可以用于将 Stream 中的元素映射为 int 类型,当调用 mapToInt() 方法时,Java 会遍历原始 Stream 中的每个元素,并将每个元素传递给指定的函数。然后,Java 会收集这些结果,最后返回返回一个 IntStream,在IntStream 上可以执行一些特殊的操作,如求和、统计、排序、最大值、最小值等

                示例:

  • 把学生信息中的年龄数据过滤到一个数组中
  • 统计所有学生信息的总年龄
  • 统计所有学生信息中的最大年龄
@Test
public void test3() {
    List<Student> list = Arrays.asList(new Student("zhangsan", 18), new Student("lisi", 19), new Student("wangwu", 17));
    //把学生信息中的年龄数据过滤到一个数组中
    int[] ageArr = list.stream().mapToInt(item -> item.getAge()).toArray();
    for (int age : ageArr) {
        System.out.println(age);
    }
    //统计所有学生信息的总年龄
    int sum = list.stream().mapToInt(item -> item.getAge()).sum();
    System.out.println(sum);
    //统计所有学生信息中的最大年龄
    Integer maxAge = list.stream().map(item -> item.getAge()).max((v1, v2) -> {
        if (v1 > v2) {
            return 1;
        } else if (v1 < v2) {
            return -1;
        }
        return 0;
    }).get();
    System.out.println(maxAge);
}

Stream#distinct

        Stream#distinct 方法用于去除 Stream 中的重复元素,它会返回由不同元素组成的新 Stream。这个方法实际上调用了 Object.equals(Object o) 方法,默认的行为是比较两个对象的引用是否相等。如果两个对象的引用相等,则认为它们相等;反之则认为它们不相等。因此,在使用 distinct 方法时,如果需要比较的元素是自定义对象,需要在自定义类中重写 equals() 和 hashCode() 方法。

        示例:

        给存在重复学生信息的集合进行去重操作并回收结果

@Test
public void test4() {
    //wangwu的信息存在重复
    List<Student> list = Arrays.asList(new Student("zhangsan", 18), new Student("lisi", 19), new Student("wangwu", 17), new Student("wangwu", 17));
    List<Student> targetList = list.stream().distinct().collect(Collectors.toList());
    Assert.isTrue(list.size() > targetList.size(), "单元测试结果与预期不匹配");
}

Stream#sorted

        Stream#sorted 方法用于对 Stream 中的元素进行排序。它返回一个包含按指定排序规则排序后元素的新的 Stream,默认情况下,使用自然顺序排序(对于实现了 Comparable 的元素类型)。

        示例

  • 自然排序,默认是升序,这里是首字母升序
  • 自定义排序,lambda表达式定义排序逻辑,这里是降序
@Test
public void test5() {
    //自然排序,默认是升序,这里是首字母升序
    List<String> names = Arrays.asList("zhangsan", "lisi", "wangwu", "zhaoliu");
    List<String> sortedCopy = names.stream().sorted().collect(Collectors.toList());
    String str = sortedCopy.stream().collect(Collectors.joining(","));
    System.out.println(str); 
    //自定义排序,lambda表达式定义排序逻辑,这里是降序
    List<Integer> ages = Arrays.asList(18, 17, 19, 20);
    List<Integer> ages2 = ages.stream().sorted((v1, v2) -> {
        if (v1 > v2) {
            return -1;
        } else if (v1 < v2) {
            return 1;
        } else {
            return 0;
        }
    }).collect(Collectors.toList());
    System.out.println(ages2.toString());
}

Stream#peek

        Stream.peek() ,它为每个元素提供了一个消费函数。该方法返回由该流的元素组成的流,并对每个元素执行所提供的 Consumer 操作方法,Consumer接口是java8的一个函数式接口,它定义了一个名为 accept 的抽象方法,该方法接受一个参数并且不返回任何结果。peek() 方法主要用于调试,以便在元素流过管道中的某个点时查看它们。peek() 是一个中间操作方法,将在调用终端方法时执行。

        示例

        打印输出以z开头的姓名;

@Test
public void test6() {
    List<String> names = Arrays.asList("zhangsan", "lisi", "wangwu", "zhaoliu");
    Stream<String> stream = names.stream()
            .peek(item -> {
                if (item.startsWith("z")) {
                    System.out.println(item);
                }
            });
    //在执行collect方法前,peek方法内的lambda表达式不会被执行;只有在终端方法collect()被调用时才会执行
    List<String> names2 = stream.collect(Collectors.toList());
    System.out.println(names2);
}

Stream#limit

        Stream#limit 方法用于限制 Stream 中元素的数量。它返回一个包含指定数量元素的新的 Stream,而不会改变原始 Stream 中的元素顺序。

        示例

        获取集合内的前两个元素

@Test
public void test7() {
    List<String> list = Arrays.asList("zhangsan", "lisi", "wangwu", "zhaoliu");
    List<String> result = list.stream().limit(2).collect(Collectors.toList());
    System.out.println(result.toString());
}

Stream#skip

        Stream#skip 方法,用于跳过 Stream 中的前 n 个元素。它返回一个新的 Stream,该 Stream 不包含原始 Stream 中的前 n 个元素。

        示例:

        跳过集合内的前3个元素,而获取剩余其他元素

@Test
public void test8() {
    List<String> list = Arrays.asList("zhangsan", "lisi", "wangwu", "zhaoliu");
    List<String> result = list.stream().skip(3).collect(Collectors.toList());
    System.out.println(result.toString());
}

Stream#forEach

        Stream#forEach 方法,用于对 Stream 中的每个元素执行遍历操作。该方法没有返回值,它只会对 Stream 中的每个元素进行遍历操作,而不会改变 Stream 中的元素或产生新的结果。

示例

@Test
public void test9() {
    List<String> list = Arrays.asList("zhangsan", "lisi", "wangwu", "zhaoliu");
    list.stream().forEach(item-> System.out.println(item));
}

Stream#forEachOrdered

        Stream#forEachOrdered方法 ,用于对 Stream 中的每个元素按照它们在 Stream 中的顺序执行一个提供的操作。与 Stream#forEach 方法不同的是,forEachOrdered方法 会保证操作的顺序与 Stream 中元素的顺序一致,而Stream#forEach方法则不保证操作的顺序。

        示例

@Test
public void test10() {
    List<String> list = Arrays.asList("zhangsan", "lisi", "wangwu", "zhaoliu");
    list.stream().forEachOrdered(item-> System.out.println(item));
}

Stream#reduce

        Stream#reduce 方法,用于将 Stream 中的元素进行某种聚合操作,并返回一个单一的结果。它接受一个 BinaryOperator 作为参数,该操作接受两个参数并返回一个结果。在聚合过程中,每个元素都会与前一个元素进行操作,并将结果传递给下一个元素,直到处理完所有元素并返回最终结果。使用 Stream#reduce 方法可以对数据进行求和、求积、求最大值、求最小值等各种聚合操作

        示例:

        求集合内所有学生信息中的学生年龄之和

@Test
public void test11() {
    List<Student> list = Arrays.asList(new Student("zhangsan", 18), new Student("lisi", 19), new Student("wangwu", 17));
    Integer totalAge = list.stream().reduce((val1, val2) -> new Student(val1.getAge() + val2.getAge())).get().getAge();
    System.out.println(totalAge);
}

Stream#collect

        Stream#collect 方法,用于将 Stream 中的元素收集到集合或其他对象中,如 List、Set、Map 等。它接受一个 Collector 作为参数,该 Collector 是一个函数式接口,用于定义将元素收集到目标集合或其他对象中的操作。

        关于Collector,可以参考Collectors类,该类内置很多静态方法,用于获取常见的Collector;

Stream#min

        Stream#min方法,用于找到 Stream 中元素的最小值。它返回 Stream 中元素的最小值,如果 Stream 为空,则返回 Optional.empty。Stream#min方法接受一个比较器作为参数,可以根据特定的业务逻辑或数据类型自定义自己的比较逻辑。

        示例

        获取集合内年龄最大的学生信息

    @Test
    public void test12() {
        List<Student> list = Arrays.asList(new Student("zhangsan", 18), new Student("lisi", 19), new Student("wangwu", 17));
        Student student = list.stream().min((v1, v2) -> {
            if (v1.getAge() > v2.getAge()) {
                return 1;
            } else if (v1.getAge() < v2.getAge()) {
                return -1;
            } else {
                return 0;
            }
        }).get();
        System.out.println(student.toString());
    }
}

Stream#max

        与Stream#min方法类似,Stream#max用于找到 Stream 中元素的最大值,Stream#max方法接受一个比较器作为参数,可以根据特定的业务逻辑或数据类型自定义自己的比较逻辑。

@Test
public void test13() {
    List<Student> list = Arrays.asList(new Student("zhangsan", 18), new Student("lisi", 19), new Student("wangwu", 17));
    Student student = list.stream().max((v1, v2) -> {
        if (v1.getAge() > v2.getAge()) {
            return -1;
        } else if (v1.getAge() < v2.getAge()) {
            return 1;
        } else {
            return 0;
        }
    }).get();
    System.out.println(student.toString());
}

Stream#count

        Stream#count方法的功能是计算Stream中元素的数量,并返回一个long类型的数值。这个方法不会将Stream中的所有元素收集到一个集合中,而是直接在流上执行计数操作,因此可以高效地计算出Stream中元素的数量。单纯使用count(),与size()效果是一样的,实际使用过程中,一般会结合其他中间方法使用,如filter();

        示例

        统计姓名集合中以z开头的元素有几个

@Test
public void test14() {
    List<String> list = Arrays.asList("zhangsan", "lisi", "wangwu", "zhaoliu");
    long num = list.stream().filter(item -> item.startsWith("z")).count();
    System.out.println(num);
}

Stream#anyMatch

        Stream#anyMatch 方法,用于判断 Stream 中的元素是否满足指定的匹配条件。如果 Stream 中至少有一个元素满足匹配条件,则返回 true;否则返回 false。

        示例

        统计学生信息集合中,是否存在有年龄小于18的学生信息

@Test
public void test15() {
    List<Student> list = Arrays.asList(new Student("zhangsan", 18), new Student("lisi", 19), new Student("wangwu", 17));
    boolean flag = list.stream().anyMatch(item -> item.getAge() < 18);
    System.out.println(flag);//结果是true
}

Stream#allMatch

        Stream#allMatch 方法用于检查 Stream 中的所有元素是否满足给定的条件函数。如果 Stream 中的所有元素都满足条件函数,则返回 true,否则返回 false,可以用在需要检查 Stream 中所有元素是否满足某个条件的场景中。

        示例

        检查学生集合集合中的学生年龄是否全部大于18

@Test
public void test16() {
    List<Student> list = Arrays.asList(new Student("zhangsan", 18), new Student("lisi", 19), new Student("wangwu", 17));
    boolean flag = list.stream().allMatch(item -> item.getAge() < 18);
    System.out.println(flag);//结果是false
}

Stream#noneMatch

        Stream#noneMatch方法,它用于检查Stream中的元素是否都不满足给定的断言条件。Stream#noneMatch方法接受一个Predicate(断言)作为参数,该断言用于测试每个元素是否满足某个条件。如果Stream中没有任何一个元素满足断言条件,则noneMatch方法返回true;否则返回false。

        示例

        检查学生信息集合中的学生姓名首字母是否都不是以a开头

@Test
public void test17() {
    List<Student> list = Arrays.asList(new Student("zhangsan", 18), new Student("lisi", 19), new Student("wangwu", 17));
    boolean flag = list.stream().noneMatch(item -> item.getName().startsWith("a"));
    System.out.println(flag);//结果是
}

Stream#findFirst

        Stream#findFirst 方法,用于查找并返回 Stream 中的第一个元素。使用 findFirst 方法可以方便地查找符合特定条件的第一个元素,而无需遍历整个 Stream。findFirst 方法不会在 Stream 为空时抛出异常,而是返回一个空的 Optional 对象。可以结合着filter方法一起使用。

        示例

        检索出学生姓名集合中学生姓名以z开头的第一个姓名

@Test
public void test18() {
    List<String> list = Arrays.asList("zhangsan", "lisi", "wangwu", "zhaoliu");
    String name = list.stream().filter(item->item.startsWith("w")).findFirst().get();
    System.out.println(name);//结果是wangwu
}

Stream#findAny

        在 Java 11 中,Stream.findAny() 方法用于在流中查找满足特定条件的第一个元素。这个方法返回一个 Optional 对象,表示可能的元素。如果流为空,则返回一个空的 Optional。

        示例

@Test
public void test19(){
    List<String> list = Arrays.asList("zhangsan", "lisi", "wangwu", "zhaoliu");
    String name = list.stream().findAny().get();
    System.out.println(name); //结果为zhangsan
    List<String> list2=new ArrayList<>();
    boolean flag = list2.stream().findAny().isEmpty();
    System.out.println(flag);//结果为true
}

Stream#of

        Stream#of() 方法,用于创建一个包含指定元素的 Stream。这个方法接收一个可迭代的数据源,如数组或集合,并返回一个包含该数据源中所有元素的 Stream。

        示例

@Test
public void test20(){
    long count = Stream.of("zhangsan", "lisi", "wangwu", "zhaoliu").count();
    System.out.println(count);
}

Stream#iterator

        Stream#iterator 方法,用于获取一个迭代器,用于遍历 Stream 中的元素。这个方法返回一个 Iterator 对象,可以使用 next() 方法依次获取 Stream 中的每个元素。

@Test
public void test21(){
    Iterator<String> iterator = Stream.of("zhangsan", "lisi", "wangwu", "zhaoliu").iterator();
    while (iterator.hasNext()){
        String next = iterator.next();
        System.out.println(next);
    }
}

下一篇:深入了解Java 8 新特性:Stream流的实践应用(二) 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/172701.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Kotlin 核心语法,为什么选择Kotlin ?

Kotlin 是一个基于 JVM 的新的编程语言&#xff0c;由 JetBrains 开发。与Java相比&#xff0c;Kotlin的语法更简洁、更具表达性&#xff0c;而且提供了更多的特性。 Kotlin是使用Java开发者的思维被创建的&#xff0c;Intellij作为它主要的开发IDE。对于 Android开发者&#…

用百度AI大模型给头像换风格

心血来潮想尝试尝试AI小应用&#xff0c;给图片加个风格&#xff08;例如微信头像&#xff09;&#xff0c;于是有了这篇简短的教程 目录 1. 领取免费资源2. 在应用列表创建应用3. 在线API调试4. 效果对比 1. 领取免费资源 网站&#xff1a;百度智能云 百度给提供了很多AIGC的…

手搓js轮播图_JavaScript进阶

手搓js轮播图 逻辑解析html结构图片切换方法圆点导航切换效果左右箭头点击切换圆点导航点击切换自动播放&#xff0c;介入暂停 完整代码 逻辑解析 css的样式我就不再进行讲述&#xff0c;如果有需求可以评论区告诉我&#xff0c;我再出一篇文章进行详细讲解 js轮播图最主要的核…

执行npm的时候报权限问题的解决方案

我们在执行npm操作的过程中&#xff0c;会出现以下权限问题&#xff0c;解决方案: 管理员身份 运行cmd 切换目录到要执行命令的文件下 再进行npm操作即可

openGauss学习笔记-129 openGauss 数据库管理-参数设置-查看参数值

文章目录 openGauss学习笔记-129 openGauss 数据库管理-参数设置-查看参数值129.1 操作步骤129.2 示例 openGauss学习笔记-129 openGauss 数据库管理-参数设置-查看参数值 openGauss安装后&#xff0c;有一套默认的运行参数&#xff0c;为了使openGauss与业务的配合度更高&…

轿车5+1汽车变速器变速箱同步器操纵机构机械结构设计CAD汽车工程

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;汽车变速器 获取完整论文报告说明书工程源文件 变速器工程图 操纵机构3D图 一、机械式变速器的概述及其方案的确定 1.1 变速器的功用和要求 变速器的功用是根据汽车在不同的行驶条件下提出的要求&#xff0c;改变发动机…

【paddlepaddle】

安装paddlepaddle 报错 ImportError: /home/ubuntu/miniconda3/envs/paddle_gan/bin/../lib/libstdc.so.6: version GLIBCXX_3.4.30 not found (required by /home/ubuntu/miniconda3/envs/paddle_gan/lib/python3.8/site-packages/paddle/fluid/libpaddle.so) 替换 /home/ubu…

【日常总结】Swagger-ui 导入 showdoc (优雅升级Swagger 2 升至 3.0)

一、场景 环境&#xff1a; 二、存在问题 三、解决方案 四、实战 - Swagger 2 升至 3.0 &#xff08;Open API 3.0&#xff09; Stage 1&#xff1a;引入Maven依赖 Stage 2&#xff1a;Swagger 配置类 Stage 3&#xff1a;访问 Swagger 3.0 Stage 4&#xff1a;获取 js…

使用sonar对webgoat进行静态扫描

安装sonar并配置 docker安装sonarqube&#xff0c;sonarQube静态代码扫描 - Joson6350 - 博客园 (cnblogs.com) 对webgoat进行sonar扫描 扫描结果 bugs Change this condition so that it does not always evaluate to "false" 意思是这里的else if语句不会执行…

3.9-Dockerfile实战

这一节介绍怎么将python程序打包成一个image&#xff0c;然后运行为一个container。 首先&#xff0c;创建/home/python/目录 mkdir /home/python/ 然后创建app.py文件。 vim app.py app.py文件的内容如下&#xff1a; from flask import Flaskapp Flask(__name__)app.route(…

【Linux】 find命令使用

find find命令是一种通过条件匹配在指定目录下查找对应文件或者目录的工具。匹配的条件可以是文件名称、类型、大小、权限属性、时间戳等。find命令还可以配合相关命令对匹配到的文件作出后续处理。 语法 find [路径...] [表达式] [path...]为需要查找文件所指定的路径。如果…

linux 开发板以太网通过Ubuntu上外网方法

在开发板嵌入式设备&#xff0c;有一个mgbe网卡&#xff0c;用网线与连接soc的网卡&#xff0c;和外接网卡&#xff0c;将网卡usb接口插入电脑&#xff0c;选择接入到Ubuntu系统 在Ubuntu将能识别到这个外接网卡&#xff0c;这样就可以通过Ubuntu和soc通讯了&#xff0c; 如下…

澳洲的猫罐头怎么样呢?几款我自己亲自喂养过的优质猫罐头推荐

一款优质的猫罐头&#xff0c;必须满足三个要点&#xff1a;完整又均衡的营养配方、新鲜又优质的原料、以及科学可靠的生产工艺。 猫罐头的三个要素&#xff0c;一个都不能少。配方不均衡&#xff0c;营养就不足&#xff1b;原料不新鲜&#xff0c;生产出来的猫罐头就不优质&a…

composer切换全局镜像源的方法

composer 默认配置中的镜像地址为国外的&#xff0c;在下载一些依赖包的时候会感觉很慢。当然国内也有很多composer镜像地址的&#xff0c;比如阿里云&#xff0c;腾讯云等。下面的博文73so博客就和大家说说&#xff0c;如何将composer的默认镜像改为国内镜像源的方法。 compo…

JAVA项目测试----用户管理系统

一)项目简介: 用户管理系统是依据于前后端分离来实现的&#xff0c;是基于Spring SpringBoot Spring MVC&#xff0c;SpringAOP&#xff0c;MyBatis等框架来实现的一个用户管理网站&#xff0c;并且已经部署到了云服务器上, 目前的用户管理系统实现了超级管理员的注册功能&…

云工作流 CloudFlow 重磅发布,流程式开发让云上应用构建更简单

云布道师 为了让企业和开发者更快速、便捷地进行云上开发&#xff0c;阿里云重磅发布云工作流&#xff08;CloudFlow&#xff09;&#xff0c;它是一款强大的面向开发者的流程编排开发工具&#xff0c;全托管、高并发、高可用&#xff0c;帮助用户简化和自动化复杂的云上业务流…

【字符编码系列二】GB2312编码

说明 GB2312是第一个汉字编码国家标准 GB 2312 标准由中国国家标准总局 1980 年发布&#xff0c;GB 即国标&#xff0c;共收录 6763 个汉字&#xff0c;其中一级汉字 3755 个&#xff0c;二级汉字 3008 个。 GB 2312 的出现&#xff0c;基本满足了汉字的计算机处理需要&#x…

手机弱网测试工具:Charles

我们在测试app的时候&#xff0c;需要测试弱网情况下的一些场景&#xff0c;那么使用Charles如何设置弱网呢&#xff0c;请看以下步骤&#xff1a; 前提条件&#xff1a; 手机和电脑要在同一局域网内 Charles连接手机抓包 一、打开Charles&#xff0c;点击代理&#xff0c;…

Prometheus监控mysql nginx tomcat 黑盒监控

部署consul_exporter https://github.com/prometheus/consul_exporter/releases/download/v0.9.0/consul_exporter-0.9.0.linux-amd64.tar.gz 注册 ootubuntu20:~# cat consul_export.json rootubuntu20:~# cat consul_export.json {"services": [{"id"…