学习Java8 Stream流,让我们更加便捷的操纵集合

news2024/11/19 15:12:08

1. 概述

本篇文章会简略的介绍一下 Lambda 表达式,然后开启我们的正题 Java8 Stream 流,希望观众老爷们多多支持,并在评论区批评指正!

Java8 的 Stream 流使用的是函数式编程模式。它可以被用来对集合或数组进行链状流式的操作,可以更方便的让我们对集合或数组操作。

2. Stream流为什么操作集合便捷?

Stream流为什么操作集合便捷?我们通过一个小例子来演示一下:

首先我们创建一个类,准备一些数据用于演示:

public class StreamDemo {

    private static List<Author> getAuthors() {
        //数据初始化
        Author author = new Author(1L,"蒙多",33,"一个从菜刀中明悟哲理的祖安人",null);
        Author author2 = new Author(2L,"亚拉索",15,"狂风也追逐不上他的思考速度",null);
        Author author3 = new Author(3L,"易",14,"是这个世界在限制他的思维",null);
        Author author4 = new Author(3L,"易",14,"是这个世界在限制他的思维",null);

        //书籍列表
        List<Book> books1 = new ArrayList<>();
        List<Book> books2 = new ArrayList<>();
        List<Book> books3 = new ArrayList<>();

        books1.add(new Book(1L,"刀的两侧是光明与黑暗","哲学,爱情",88,"用一把刀划分了爱恨"));
        books1.add(new Book(2L,"一个人不能死在同一把刀下","个人成长,爱情",99,"讲述如何从失败中明悟真理"));

        books2.add(new Book(3L,"那风吹不到的地方","哲学",85,"带你用思维去领略世界的尽头"));
        books2.add(new Book(3L,"那风吹不到的地方","哲学",85,"带你用思维去领略世界的尽头"));
        books2.add(new Book(4L,"吹或不吹","爱情,个人传记",56,"一个哲学家的恋爱观注定很难把他所在的时代理解"));

        books3.add(new Book(5L,"你的剑就是我的剑","爱情",56,"无法想象一个武者能对他的伴侣这么的宽容"));
        books3.add(new Book(6L,"风与剑","个人传记",100,"两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢?"));
        books3.add(new Book(6L,"风与剑","个人传记",100,"两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢?"));

        author.setBooks(books1);
        author2.setBooks(books2);
        author3.setBooks(books3);
        author4.setBooks(books3);

        List<Author> authorList = new ArrayList<>(Arrays.asList(author,author2,author3,author4));
        return authorList;
    }
}
复制代码

假如我们对该作家列表进行操作,要求对作家列表进行去重,并过滤年龄小于18的作家,然后依次打印作者姓名和年龄。

我们不使用 Stream 流我们可以这样写:

    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        List<Author> fauthors = new ArrayList<>();

        //进行去重
        for (Author author : authors){
            if (!fauthors.contains(author)){
                fauthors.add(author);
            }
        }
        authors.clear();
        //筛选出年龄小于18的
        for (Author author : fauthors){
            if(author.getAge() < 18){
                authors.add(author);
            }
        }

        //输出姓名
        for (Author author : authors){
            System.out.println(author.getName() + " : " + author.getAge());
        }


    }
复制代码

我们可以发现这种方式非常繁琐,且难懂。

如果我们使用 stream 流的话,代码就非常简单直观了。

public class StreamDemo {

    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        //把集合转换成流,进行stream流操作
        authors.stream()
                .distinct() //去重
                .filter(author -> author.getAge() < 18)//过滤
                .forEach(author -> System.out.println(author.getName())); //打印年龄
    }
}
复制代码

3. 正式学习之前我们先学习一下Lambda表达式

Lambda 表达式是 JDK8中的一个语法糖。它可以对某些匿名内部类的写法进行简化。它是函数式编程思想的一个重要体现。让我们不用关注是什么对象,而关注于我们对数据进行了什么操作

核心原则:可推导可省略

3.1. 基本格式

(参数列表)->代码

例1:

public class Test1 {

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("hi");
            }
        }).start();
    }

}
复制代码
public class Test1 {

    public static void main(String[] args) {
        new Thread(()->{
            System.out.println("hi");
        }).start();
    }

}
复制代码

例2:

现有方法定义如下,其中 InitBinaryOperator 是一个接口。先使用匿名内部类的写法调用该方法。

public class Test2 {

    public static int calculateNum(IntBinaryOperator operator){
        int a = 10;
        int b = 10;
        return operator.applyAsInt(a,b);
    }

    public static void main(String[] args) {
        int i = calculateNum(new IntBinaryOperator() {
            @Override
            public int applyAsInt(int left, int right) {
                return left + right;
            }
        });
        System.out.println(i);
    }

}
复制代码

使用 Lambda 表达式的写法:

public class Test2 {

    public static void main(String[] args) {
        //++++++++++++++lambda表达式写法+++++++++++++++
        int i1 = calculateNum((int left, int right) -> {
            return left + right;
        });
        System.out.println(i1);
    }
}
复制代码

例3:现有方法定义如下,其中 intPredicate 是一个接口。先使用匿名内部类的写法调用该方法。

public class Test3 {

    /**
     *
     * @param predicate IntPredicate接口,实现接口方法 test用于判断数据满足条件
     */
    public static void printNum(IntPredicate predicate){
        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        for(int i: arr){
            if(predicate.test(i)){
                System.out.println(i);
            }
        }
    }

    public static void main(String[] args) {
        printNum(new IntPredicate() {
            @Override
            public boolean test(int value) {
                //判断当前参数是否是偶数
                if(value%2 == 0) return true;
                return false;
            }
        });
    }

}
复制代码

使用 Lambda 表达式的写法:

public class Test3 {

    public static void main(String[] args) {

        System.out.println("+++++++++++++lambda表达式写法++++++++++++++++");
        //+++++++++++++lambda表达式写法++++++++++++++++
        printNum((int value) ->{
            return value%2 == 0;
        });
    }

}
复制代码

例4:现有方法定义如下,其中 Function 是一个接口。先使用匿名内部类的写法调用该方法。

public class Test4 {

    public static <R> R typeConver(Function<String, R> function){
        String str = "1235";
        R result = function.apply(str);
        return result;
    }

    public static void main(String[] args) {
        Integer integer = typeConver(new Function<String, Integer>() {

            //对字符串进行处理,返回结果
            @Override
            public Integer apply(String s) {
                return s.length();
            }

        });
        System.out.println(integer);

    }

}
复制代码

使用 Lambda 表达式写法:

public class Test4 {

    public static void main(String[] args) {
  
        System.out.println("+++++++++++++lambda表达式写法++++++++++++++++");
        Integer integer1 = typeConver((String s) -> {
            return s.length();
        });
        System.out.println(integer1);

    }

}
复制代码

例5:现有方法定义如下,其中 IntConsumer 是一个接口。先使用匿名内部类的写法调用该方法。

public class Test5 {

    public static void foreachArr(IntConsumer consumer){
        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        for (int i : arr){
            consumer.accept(i);
        }
    }

    public static void main(String[] args) {
        foreachArr(new IntConsumer() {

            //对数据进行处理
            @Override
            public void accept(int value) {
                System.out.println(value*2);
            }
        });
    }

}
复制代码

使用 Lambda 表达式写法:

public class Test5 {

    public static void main(String[] args) {

        System.out.println("+++++++++++++lambda表达式写法++++++++++++++++");
        foreachArr((int value) ->{
            System.out.println(value * 2);
        });
    }

}
复制代码

3.2. 省略规则

  1. 参数类型可以省略
  2. 方法体只有一句代码时大括号{}、return以及一行代码后的 ; 号可以省略
  3. 方法只有一个参数时小括号可以省略

如:

public class Test5 {

    public static void main(String[] args) {
        foreachArr(new IntConsumer() {

            //对数据进行处理
            @Override
            public void accept(int value) {
                System.out.println(value*2);
            }
        });

        System.out.println("+++++++++++++lambda表达式写法++++++++++++++++");
        foreachArr((int value) ->{
            System.out.println(value * 2);
        });

        System.out.println("+++++++++++++lambda表达式省略写法++++++++++++++++");
        foreachArr(value -> System.out.println(value * 2));
    }

}
复制代码

4. 常用操作

4.1. 创建流

单列集合:集合对象.stream()

List<Author> authors = getAuthors();
Stream<Author> stream = authors.stream();
复制代码

数组:Arrays.stream(数组)或者使用 Steam.of(数组)来创建

Integer[] arr = {1, 2, 3, 4, 5};
Stream<Integer> stream = Arrays.stream(arr);
Stream<Integer> stream2 = Steam.of(arr);
复制代码

双列集合:转换成单列集合后再创建

Map<String, Integer> map = new HashMap<>();
map.put("1", 19);
map.put("2", 19);
map.put("3", 19);
Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream();
复制代码

4.2. 中间操作

  1. filter() 方法,可以对流中的元素进行条件过滤,符合过滤条件的才能继续留在流中。
public static void printAllAuthors(){
    List<Author> authors = getAuthors();
    authors.stream().filter(author -> author.getName().length() > 1)
        .forEach(author -> {
            System.out.println(author.getName());
        });
}
复制代码
  1. map() 方法,可以把流中元素进行计算或者转换,使其返回新的值(覆盖原先的值)。相当于一种映射操作。操作之后,返回改变后新的流元素。
public static void test4(){
    List<Author> authors = getAuthors();
    authors.stream().map(author -> author.getName())
        .forEach(name -> {
            System.out.println(name);
        });
}
复制代码

  1. distinct() 方法,可以去除流中重复的元素
public static void test5(){
    List<Author> authors = getAuthors();
    authors.stream()
        .distinct()
        .map(author -> author.getName())
        .forEach(name -> System.out.println(name));
}
复制代码

注意:distinct() 方法是依赖 Objects 的 equals() 方法来判断对象是否相同。自定义对象实体类,注意重写 equals() 和 hashCode() 方法。

  1. sorted 方法,可以对流中的元素进行排序。
public static void test6(){
    List<Author> authors = getAuthors();
    authors.stream()
        .distinct()
        .sorted((o1, o2) -> o1.getAge() - o2.getAge())
        .forEach(author -> System.out.println(author.getAge()));
}
复制代码

sorted() 方法传入一个比较器 Comparator,实现 compare() 方法,传入比较规则。

public static void test6(){
    List<Author> authors = getAuthors();
    authors.stream()
        .distinct()
        .sorted(new Comparator<Author>() {
            @Override
            public int compare(Author o1, Author o2) {
                return o1.getAge() - o2.getAge();
            }
        })
        .forEach(author -> System.out.println(author.getAge()));
}
复制代码
  1. limit() 方法,可以设置流的最大长度,超出的部分将被抛弃。
private static void test7() {
    List<Author> authors = getAuthors();
    authors.stream()
        .distinct()
        .sorted((a1, a2) -> a2.getAge() - a1.getAge())
        .limit(2)
        .forEach(author -> System.out.println(author.getName()));
}
复制代码

对这个流分析图有些疑惑,为什么sorted 和 limit 中间操作的结果一致呢?

  1. skip() 方法,跳过流中的前 n 个元素,返回剩下的元素。
private static void test8() {
    List<Author> authors = getAuthors();
    authors.stream()
        .distinct()
        .sorted((a1, a2) -> a2.getAge() - a1.getAge())
        .skip(1)
        .forEach(a -> System.out.println(a.getName()));
}
复制代码

  1. flatMap() 方法,map 只能把一个对象转换成另一个对象来作为流中的元素。而 flatMap 可以把一个对象转换为多个对象作为流中的元素。

我们使用 map 来操作,发现不能进行去重,因为映射出来的是包含书籍列表的流。

private static void test9() {
    List<Author> authors = getAuthors();
    authors.stream()
        .map(author -> author.getBooks())
        .forEach(books -> System.out.println(books));
}
复制代码

当我们使用 flatMap 进行操作时,会把映射出来的列表中的元素拿出来进行合并作为流对象进行操作。

private static void test9() {
    List<Author> authors = getAuthors();
    authors.stream()
        .flatMap(author -> author.getBooks().stream())
        .distinct()
        .forEach(book -> System.out.println(book));
}
复制代码

4.3. 终结操作

4.3.1. forEach、count、max/min、collect

  1. forEach() 方法,对流中的元素进行遍历操作,我们通过传入的参数去指定对遍历到的当前院所进行的是什么具体操作。
private static void test10() {
    List<Author> authors = getAuthors();
    authors.stream()
        .distinct()
        .forEach(author -> System.out.println(author.getName()));
}
复制代码

  1. count() 方法,可以用来获取当前流中元素的个数。
private static void test11() {
    List<Author> authors = getAuthors();
    long count = authors.stream()
        .flatMap(author -> author.getBooks().stream())
        .distinct()
        .count();
    System.out.println("书籍总数量:" + count);
}
复制代码

  1. min() 和 max() 方法,可以用来求流中的最值。

注意:使用 min 或者 max 方法需要传入一个比较器实现具体的排序规则,为什么要这样做呢?因为你操作的流是多个书籍对象,假如你要获取书籍评分最高的书籍对象,那么需要传入具体的比较规则,才能获取到最高评分的数据对象。

这与我们想象的不同,我们以为是对一组数取最大值,那样就不需要实现比较器。而stream 流为了实现统一,所以需要传入比较器规则。

min 和 max 方法相当于经过排序 sorted 和 limit 限制后的结果。

注意一旦做出终结操作,流自动关闭,那么该流对象就不能再进行操作了。

实战

注意:获取一组对象的最大值和最小值它们的比较规则应是相同的,而不是相反的。

private static void test12() {
    List<Author> authors = getAuthors();
    Optional<Integer> max = authors.stream()
        .flatMap(author -> author.getBooks().stream())
        .map(book -> book.getScore())
        .max((s1, s2) -> s1 - s2);
    System.out.println("最大值:" + max.get());

    Optional<Integer> min = authors.stream()
        .flatMap(author -> author.getBooks().stream())
        .map(book -> book.getScore())
        .min((s1, s2) -> s1 - s2);

    System.out.println("最小值:" + min.get());

}
复制代码

  1. collect() 方法,把当前流转换成一个集合,收集。

collect() 方法需要传入一个参数,指定流转换集合的类型。

Collectors通过该工具类指定集合的类型

private static void test13() {
    List<Author> authors = getAuthors();
    List<String> collect = authors.stream()
        .distinct()
        .map(author -> author.getName())
        .collect(Collectors.toList());
    System.out.println(collect);
}
复制代码

private static void test14() {
    List<Author> authors = getAuthors();
    Set<String> collect = authors.stream()
        .flatMap(author -> author.getBooks().stream())
        .map(book -> book.getName())
        .collect(Collectors.toSet());
    System.out.println(collect);

}
复制代码

private static void test15() {
    List<Author> authors = getAuthors();
    Map<String, List<Book>> collect = authors.stream()
        .distinct()
        //分别指定键和值的映射
        .collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));
    System.out.println(collect);
}
复制代码

4.3.2. 查找与匹配

匹配,结果为 boolean 类型

  1. anyMatch() 方法,当流中至少有一个元素符合判断条件,就返回 true

需要传入一个判断条件,跟 filter方法的过滤条件类似。

private static void test16() {
    List<Author> authors = getAuthors();
    boolean b = authors.stream()
        .distinct()
        .anyMatch(author -> author.getAge() > 29);
    System.out.println(b ? "存在29岁以上作家" : "不存在");
}
复制代码

  1. allMatch() 方法,当流中所有元素都满足判断条件,就返回 true
private static void test17() {
    List<Author> authors = getAuthors();
    boolean b = authors.stream()
        .distinct()
        .allMatch(author -> author.getAge() > 16);
    System.out.println(b ? "作家年龄都大于16岁" : "不匹配");
}
复制代码

  1. noneMatch() 方法,当流中所有元素都不符合判断条件,返回 true
private static void test18() {
    List<Author> authors = getAuthors();
    boolean b = authors.stream()
        .distinct()
        .noneMatch(author -> author.getAge() > 100);
    System.out.println(b ? "作家年龄都不大于100岁" : "作家年龄都大于100岁");

}
复制代码


查找

  1. findAny() 方法,获取流中任意一个元素,该方法不能保证获取的一定是流中第一个元素。
private static void test19() {
    List<Author> authors = getAuthors();
    Optional<Author> any = authors.stream()
        .distinct()
        .filter(author -> author.getAge() > 16)
        .findAny();
    System.out.println(any.get());
}
复制代码

  1. findFirst() 方法,获取流中的第一个元素。
private static void test20() {
    List<Author> authors = getAuthors();
    Optional<Author> first = authors.stream()
        .distinct()
        .sorted((a1, a2) -> a1.getAge() - a2.getAge())
        .findFirst();
    first.ifPresent(author -> System.out.println(author.getName()));
}
复制代码

4.3.3. reduce归并

reduce 归并,对流中的数据按照指定的计算方式计算出一个结果(缩减操作)。

reduce 的作用就是把 stream 流中的元素组合起来,我们可以传入一个初始值,它会按照我们的计算方式依次拿流中的元素和初始值进行计算后返回结果,结果再和后面的元素计算(累加)。

reduce()方法有三种重载,如下图。

第一种重载,其内部的计算方式如下:

T result = identity;
for(T element : this.stream){
    result = accumulator.apply(result, element);
}
return result;
复制代码

其中 identity 就是我们可以通过方法参数传入的初始值, accumulator的 apply() 方法,具体进行扫描计算也是通过我们传入的方法参数来确定的。


第二种重载,其内部的计算方式如下:

boolean foundAny = false;
T result = null;
for (T element : this stream) {
    if (!foundAny) {
        foundAny = true;
        result = element;
    }
    else
        result = accumulator.apply(result, element);
}
return foundAny ? Optional.of(result) : Optional.empty();
复制代码

第二种重载方式,由于没有初始值,其内部会在第一次循环时,对 foundAny 进行判断,满足将stream 流中的第一个元素,赋值给初始值,然后进行循环计算。这种方式适用于与自身进行一些运算。


举例

  1. 使用reduce求所有作者年龄的和
private static void test21() {
    List<Author> authors = getAuthors();
    Integer reduce = authors.stream()
        .map(author -> author.getAge())
        .reduce(0, (result, age) -> result + age);
    System.out.println(reduce);
}
复制代码

这种方式计算所有作者年龄的和,reduce() 方法需要传入两个参数,第一个传入初始值(指定 result 初始值);第二个传入计算规则:result代表结果, age 代表下一个需要累加的值,累加完毕后返回结果给 result ,然后重新累加。

  1. 使用 reduce 求所有作者中年龄的最大值
private static void test22() {
    List<Author> authors = getAuthors();
    Integer max = authors.stream()
        .map(author -> author.getAge())
        .reduce(Integer.MIN_VALUE, (result, age) -> result < age ? age : result);
    System.out.println(max);
}
复制代码

  1. 使用 reduce 求所有作者中年龄的最小值
private static void test23() {
    List<Author> authors = getAuthors();
    Integer min = authors.stream()
        .map(author -> author.getAge())
        .reduce(Integer.MAX_VALUE, (result, age) -> result > age ? age : result);
    System.out.println(min);
}
复制代码

  1. 通过reduce 第二种重载,求所有作者中年龄的最小值
private static void test24() {
    Optional<Integer> minOptional = getAuthors().stream()
        .map(author -> author.getAge())
        .reduce((result, age) -> result < age ? result : age);
    minOptional.ifPresent(min -> System.out.println(min.intValue()));
}
复制代码

5. 注意事项

  1. 不要惰性求值(如果没有终结操作,中间操作是不会得到执行的)
  2. 流是一次性的(一旦一个流对象经过一个终结操作后,这个流就不能再被使用)
  3. 不会影响原数据(我们在流中可以对数据做很多处理,不会对原数据有影响)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

推荐系统基本问题及系统优化路径

省时查报告-专业、及时、全面的行研报告库省时查方案-专业、及时、全面的营销策划方案库【免费下载】2022年10月份热门报告盘点大规模推荐类深度学习系统的设计实践.pdf荣耀推荐算法架构演进实践.pdf推荐系统在腾讯游戏中的应用实践.pdf清华大学256页PPT元宇宙研究报告.pdf&…

产品设计杂感

概述 前面多篇文章提过我近一年以来几乎是一个人在负责一款数据产品&#xff0c;一款公司内部使用的报表开发工具。市面上的类似产品如Tableau&#xff0c;QuickBI等。工作角色&#xff08;职责&#xff09;包括&#xff1a;后端开发&#xff0c;前端开发&#xff0c;功能测试…

STM32 bootloader简单实现的验证

目录 背景知识 STM32的启动模式 Flash memory的大小 实验验证 分区分配 bootloader代码 systeminit 背景知识 STM32的启动模式 STM32有三种启动模式, 这里验证的bootloader是通过Flash memory启动方式, 使用STM32内置的Flash,其首地址是0x08000000&#xff0c;一般我们…

[论文阅读] 颜色迁移-梯度保护颜色迁移

[论文阅读] 颜色迁移-梯度保护颜色迁移 文章: [Gradient-Preserving Color Transfer], [代码未公开] 本文目的: 如题所示为梯度保护的颜色迁移方法. 1-算法原理 人类的视觉系统对局部强度差异比强度本身更敏感, 因而, 保持颜色梯度是场景保真度的必要条件, 因而作者认为: 一…

python+django留守儿童爱心捐赠网站

开发语言&#xff1a;Python 框架&#xff1a;django Python版本&#xff1a;python3.7.7 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;PyCharm 目录 1 绪论 1 1.1课题背景 1 1.2课题研究现状 1 1.3初步设计方法与实施方案 2 1.4本文研究…

城市应急处置系统实施目标

针对需求分析中的业务目标&#xff0c;本系统在实施中&#xff0c;通过 “两个工作台七个子系统”的目标来支撑业务目标&#xff0c;满足系统延续需求、功能需求、制度建设需求、平台拓展需求和技术性能需求。 具体分为事前6个子系统、事中2个工作台和事后1个子系统这三方面目标…

002:UIView

UIView简介&#xff1a; UIView作为最基础的视图类&#xff0c;起着管理屏幕上一定区域内容展示的作用。作为各种视图的父类&#xff0c;提供相应的基础能力。 外观、渲染和动画。相应区域内的事件。布局和管理子视图。 布局&#xff1a; 设置自身大小&#xff08;size&…

[附源码]Python计算机毕业设计SSM基于农产品交易系统(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

动态代理:JDK动态代理源码学习

文章目录前言概述什么是代理静态代理动态代理正文入口方法1&#xff1a;newProxyInstance方法2&#xff1a;getProxyClass0方法3&#xff1a;get 获取代理方法4&#xff1a;apply 创建代理方法5&#xff1a;generateProxyClass方法6&#xff1a;generateClassFile代理类总结前言…

LeetCode_动态规划_困难_1691.堆叠长方体的最大高度

目录1.题目2.思路3.代码实现&#xff08;Java&#xff09;1.题目 给你 n 个长方体 cuboids &#xff0c;其中第 i 个长方体的长宽高表示为 cuboids[i] [widthi, lengthi, heighti]&#xff08;下标从 0 开始&#xff09;。请你从 cuboids 选出一个子集 &#xff0c;并将它们堆…

ubuntu14.04搭建openGrok 1.7.40 + Java17+tomcat10.0.27阅读android系统代码

为了快速阅读android系统代码&#xff0c;首选openGrok&#xff0c;其它SI或understand估计不适合了。 话不多说&#xff0c;工欲善其事必先利其器&#xff0c;先下载源码和工具. 以下命令默认使用root&#xff0c;防止权限问题 一、下载android 代码 还是清华的镜像比较牛…

农村金融专题-保险支出、收入、补贴各省份涉农贷款数据集

一、31省市农业保险赔付支出 1、数据来源&#xff1a;wind数据库 2、时间跨度&#xff1a;2005-2019年 3、区域范围&#xff1a;全国 4、指标说明&#xff1a; 部分数据如下&#xff1a; 二、各省农业保险保费收入 1、数据来源&#xff1a; 中国保险数据 2、时间跨度&…

「杂谈·II」cmp() 的参数类型应该是啥?

0. 引言 上了一节 DS 课&#xff0c;但是回到了初学 C 的内容…… 众所周知&#xff0c;最小生成树的 Kruskal 要用边表排序&#xff0c;通常是 sort() 配 cmp()。 而 cmp() 的两个参数的类型最好是什么呢&#xff1f; 让我们回到初学 C 的时候&#xff0c;温习一下知识…… 1…

MySQL数据库学习(3)

MySQL中select语句语法简单介绍&#xff1a; 基本语法规则&#xff1a; SELECT {* | <字段列名>} [FROM <表 1>, <表 2>… [WHERE <表达式> [GROUP BY <group by definition> [HAVING <expression> [{<operator> <expression>…

FineReport商业智能数据分析-下拉框控件

1. 概述 1.2 应用场景 「下拉框控件」可应用于填报、参数等场景&#xff0c;本文将介绍「下拉框控件」的属性及应用。 1.2.1 填报控件 填报报表中&#xff0c;可以用来在多个预备选项中选择一个值填入。如下图所示&#xff1a; 1.2.2 参数控件 参数面板处可以通过该控件过…

微服务框架 SpringCloud微服务架构 微服务保护 31 限流规则 31.4 流控效果【warm up】

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 微服务保护 文章目录微服务框架微服务保护31 限流规则31.4 流控效果【warm up】31.4.1 流控效果31.4.2 流控效果 - warm up31.4.3 案例31 限…

[论文阅读] 颜色迁移-Illuminant Aware Gamut-Based

[论文阅读] 颜色迁移-Illuminant Aware Gamut-Based 文章: [Illuminant Aware Gamut-Based Color Transfer], [python代码] 本文目的是提出一种新的颜色迁移算法, 可以感知光源变化的全色域颜色迁移方法. 1-算法原理 图像是由摄像机对光谱场景内容和场景照度的敏感性所产生…

springboot validated注解数据校验 异常处理

springboot validated 数据校验validated 数据校验简单的写一下这个用法啊&#xff0c;清晰的本篇文章就记录这个注解的一个用法。validated 数据校验 我们一般的数据校验是怎么用的&#xff1f;在常规模式下我们可能就是在前端去通过js去判断&#xff1f;还是在后端重新查找数…

【C语言字符串相关函数大全】

【C语言字符串相关函数大全】【1】atof【2】atoi【3】atol【4】isalnum【5】isdigit【6】islower【7】isupper【8】isprint【9】memchr【10】memcmp【11】memcpy【12】memset【13】strcat【14】strchr【15】strcmp【16】strpbrk【17】strstr【18】strtok【19】源码【20】源码执…

Mipmap的作用以及其优势和缺点

Mipmap的作用以及其优势和缺点 定义 Mipmap,又叫做多级渐进贴图纹理映射,作用在游戏的纹理贴图,根据渲染物体距离相机的远近,选用不同大小的纹理贴图; 作用 可以使得远处的像素不发生闪烁;减小带宽;减小带宽的原理 说到MipMap可能很多人都会觉得,只是开启后会增加内…