JDK8新特性之Steam流

news2025/6/9 14:20:12

这里写目录标题

  • 一、Stream流概述
    • 1.1、传统写法
    • 1.2、Stream写法
    • 1.3、Stream流操作分类
  • 二、Stream流获取方式
    • 2.1、根据Collection获取
    • 2.2、通过Stream的of方法
  • 三、Stream常用方法介绍
    • 3.1、forEach
    • 3.2、count
    • 3.3、filter
    • 3.4、limit
    • 3.5、skip
    • 3.6、map
    • 3.7、sorted
    • 3.8、distinct
    • 3.9、match
    • 3.10、find
    • 3.11、max和min
    • 3.12、reduce方法
      • 3.12.1、 map和reduce的组合
    • 3.13、mapToInt
    • 3.14、concat
    • 3.15、综合案例
    • 4.1、结果收集到集合中
  • 四、Stream结果手集
    • 4.1、结果收集到集合中
    • 4.2、结构收集到数组中
    • 4.3、对流中数据做聚合操作
    • 4.4、对流中数据做分组操作
    • 4.5、对流中数据做分区操作
    • 4.6、对流中数据做拼接
  • 五、并行Stream流
    • 5.1、串行的Stream流
    • 5.2、并行流
      • 5.2.1、获取并行流
      • 5.2.3、并行流操作
    • 5.3、并行流和串行流对比
    • 5.4、线程安全

一、Stream流概述

Java 中,Stream 是一个来自java.util.stream包的接口,用于对集合(如List、Set等)或数组等数据源进行操作的一种抽象层。
Stream流(和IO流没有任何关系)主要是对数据进行加工处理的。Stream API能让我们快速完成许多复杂的操作,如筛选、切片、映射、查找、去除重复,统计,匹配和归约。

1.1、传统写法

现在有需求:对list中姓张,名字长度为3的信息打印:

	public static void main(String[] args) {
        //定义一个List集合
		List<String> list = Arrays.asList("张三","张三丰","张无忌","李四","王五");
		//获取姓张,名字长度为3的信息,添加到列表中
		List<String> list1=new ArrayList<>();
		for (String s : list) {
			if(s.startsWith("张")&&s.length()==3){
				list1.add(s);
			}
		}
		for (String s : list1) {
			System.out.println(s);
		}
	}

1.2、Stream写法

    public static void main(String[] args) {
        //定义一个List集合
        List<String> list = Arrays.asList("张三","张三丰","张无忌","李四","王五");
        list.stream().filter(s -> s.startsWith("张"))
                .filter(s -> s.length()== 3)
                .forEach(System.out::println);
    }

上面的SteamAPI代码的含义:获取流,过滤张,过滤长度,逐一打印。代码相比于上面的案例更加的简洁直观。

1.3、Stream流操作分类

  • 生成操作
    通过数据源(集合、数组等)生成流。
  • 中间操作
    对流进行某种程度的过滤/映射,并返回一个新的流。
  • 终结操作
    执行某个终结操作,一个流只能有一个终结操作。

二、Stream流获取方式

2.1、根据Collection获取

java.util.Collection 接口中加入了default方法 stream,也就是说Collection接口下的所有的实现都可以通过steam方法来获取Stream流。(java集合框架主要包括两种类型的容器,一种是集合,存储一个元素集合(Collection),另一种是图(Map),存储键/值对映射)。

    public static void main(String[] args) {
        List<String> list=new ArrayList<>();
        Stream<String> stream=list.stream();
        Set<String> set=new HashSet<>();
        Stream<String> stream1=set.stream();
        Vector vector=new Vector();
        vector.stream();
    }

Map接口别没有实现Collection接口,这时我们可以根据Map获取对应的key value的集合。

    public static void main(String[] args) {
        Map<String,Object> map=new HashMap<>();
        Stream<String> stream=map.keySet().stream();//key
        Stream<Object> stream1=map.values().stream();//value
        Stream<Map.Entry<String,Object>> stream2=map.entrySet().stream();//entry
    }

2.2、通过Stream的of方法

由于数组对象不可能添加默认方法,所有Stream接口中提供了静态方法of操作到数组中的数据

    public static void main(String[] args) {
        Stream<String> a1= Stream.of("a1","a2","a3");
        String[] arr1 = {"aa","bb","cc"};
        Stream<String> arr11 = Stream.of(arr1);
        Integer[] arr2 = {1,2,3,4};
        Stream<Integer> arr21 = Stream.of(arr2);
        arr21.forEach(System.out::println);
        // 注意:基本数据类型的数组是不行的
        int[] arr3 = {1,2,3,4};
        Stream.of(arr3).forEach(System.out::println);
    }

三、Stream常用方法介绍

Stream常用方法

方法名方法作用返回值类型防范种类
count统计个数long终结
forEach逐一处理void终结
filter过滤Stream函数拼接
limit取用前几个Stream函数拼接
skip跳过前几个Stream函数拼接
map映射Stream函数拼接
concat组合Stream函数拼接
注意:
  1. 这里把常用的API分为“终结方法”和“非终结方法”
  2. “终结方法”:返回值类型不再是 Stream 类型的方法,不再支持链式调用。
  3. “非终结方法”:返回值类型仍然是 Stream 类型的方法,支持链式调用。
  4. Stream方法返回的是新的流。
  5. Stream不调用终结方法,中间的操作不会执行。

3.1、forEach

forEach用来遍历流中的数据的。

void forEach(Consumer<? super T> action);

该方法接受一个Consumer接口,会将每一个流元素交给函数处理。

    public static void main(String[] args) {
        Stream<String> a1=Stream.of("aa","bb","cc");
        a1.forEach(System.out::println);
    }

3.2、count

Stream流中的count方法用来统计其中的元素个数的。

  long count();

该方法返回一个long值,代表元素的个数。

    public static void main(String[] args) {
        long count = Stream.of("a1", "a2", "a3").count();
        System.out.println(count);
    }

3.3、filter

filter方法的作用是用来过滤数据的。返回符合条件的数据。
可以通过filter方法将一个流转换成另一个子集流。

    public static void main(String[] args) {
        Stream<String> stream =
                Stream.of("aa", "ab", "bc","a1","b2","c3").
                        filter(s -> s.contains("a"));
        stream.forEach(System.out::println);
    }

该接口接收一个Predicate函数式接口参数作为筛选条件。

3.4、limit

limit方法可以对流进行截取处理,支取前n个数据,

  Stream<T> limit(long maxSize);

参数式一个long类型的数值,如果集合当前长度大于参数就进行截取,否则不操作:

      public static void main(String[] args) {
        Stream.of("a1", "a2", "a3","bb","cc","aa","dd")
                .limit(3)
                .forEach(System.out::println);
    }

3.5、skip

如果希望跳过前面几个元素,可以使用skip方法获取一个截取之后的新流:

  Stream<T> skip(long n);

示例:

    public static void main(String[] args) {
       Stream.of("a1","b2","c3","aa","bb","cc")
               .skip(3).forEach(System.out::println);
    }

3.6、map

如果需要将流中的元素映射到另一个流中,可以使用map方法:

  <R> Stream<R> map(Function<? super T, ? extends R> mapper);

该接口需要一个Function函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的数据

    public static void main(String[] args) {
        Stream.of("1","2","3","4","5")
                //.map(s -> Integer.parseInt(s))
                .map(Integer::parseInt)
                .forEach(System.out::println);
    }

3.7、sorted

如果需要将数据排序,可以使用sorted方法:

  Stream<T> sorted();

在使用的时候可以根据自然规则排序,也可以通过比较强来指定对应的排序规则

      public static void main(String[] args) {
        Stream.of("1","2","7","9","3","4","6")
                .map(Integer::parseInt)
                .sorted((o1, o2) -> (o1 - o2))
                .forEach(System.out::println);
    }

3.8、distinct

如果要去掉重复数据,可以使用distinct方法

	Stream<T> distinct();  

Stream流中的distinct方法对于基本数据类型式可以直接去重的,但是对于自定义类型,我们需要重写hashCode和equals方法来移除重复数据。

    public static void main(String[] args) {
        Stream.of("1","2","4","5","2","3","4")
                .sorted()
                .distinct().forEach(System.out::println);
        System.out.println("----------------");
        Stream.of(
                new Person("张三",18),
                new Person("李四",18),
                new Person("王五",20),
                new Person("张三",18)
            ).distinct().forEach(System.out::println);
    }  

3.9、match

如果需要判断数据是否匹配指定的条件,可以使用match相关的方法:

boolean anyMatch(Predicate<? super T> predicate); // 元素是否有任意一个满足条件
boolean allMatch(Predicate<? super T> predicate); // 元素是否都满足条件
boolean noneMatch(Predicate<? super T> predicate); // 元素是否都不满足条件

使用:

    public static void main(String[] args) {
        boolean b = Stream.of("1","2","3","4","5","7")
                .map(Integer::parseInt)
                //.anyMatch(s-> s > 4);
                //.allMatch(s-> s > 4);
                .noneMatch(s-> s > 4);
        System.out.println(b);
    }  

注:match是一个终结方法。

3.10、find

如果我们需要找到某些数据,可以使用find方法来实现

	Optional<T> findFirst();
	Optional<T> findAny();

使用:

    public static void main(String[] args) {
        Optional<String> first = Stream.of("a", "b", "c")
                .findFirst();
        System.out.println(first.get());

        Optional<String> any = Stream.of("a", "b", "c","d")
                .findAny();
        System.out.println(any.get());
    }

注:

3.11、max和min

如果我们想要获取最大值和最小值,那么可以使用max和min方法

    public static void main(String[] args) {
        Optional<Integer> max= Stream.of(1,2,3,4).max(Integer::compareTo);
        System.out.println(max.get());
        Optional<Integer> min= Stream.of(1,2,3,4).min(Integer::compareTo);
        System.out.println(min.get());
    }  

3.12、reduce方法

如果需要将所有数据归纳得到一个数据,可以使用reduce方法:

    public static void main(String[] args) {
        Integer sum = Stream.of(4,5,3,7)
                //identity默认值
                //第一次的时候会将默认值赋给x
                //之后每次将上一次的操作结果赋值给x y,就是每次从数据中获取的元素
                .reduce(0, (x, y) -> {
                    System.out.println("x="+x+",y="+y);
                    return x + y;
                });
        System.out.println("sum = " + sum);
        // 获取最大值
        Integer max = Stream.of(4,5,3,9)
                .reduce(0,(x,y) ->{
                    return x>y?x:y;
                });
        System.out.println("max = " + max);
    }  

3.12.1、 map和reduce的组合

在实际开发中我们经常会将map和reduce一块来使用:

    public static void main(String[] args) {
        //1、求出所有年龄总和
        Integer sumAge= Stream.of(
                new Person("张三", 20),
                new Person("李四", 21),
                new Person("王五", 22),
                new Person("赵六", 23)
        ).map(Person::getAge)
                .reduce(0,Integer::sum);
        System.out.println(sumAge);

        //2、求出所有年龄最大值
        Integer maxAge= Stream.of(
                new Person("张三", 20),
                new Person("李四", 21),
                new Person("王五", 22),
                new Person("赵六", 23)
        ).map(Person::getAge)
                .reduce(Integer::max).get();
        System.out.println(maxAge);

        //3、统计字符 a 出现的次数
        Integer countA= Stream.of("a","b","c","d","e","a","a","a")
                .map(ch -> ch.equals("a")?1:0)
                .reduce(0,Integer::sum);
        System.out.println(countA);
    }  

3.13、mapToInt

如果需要将Sream中的Integer类型转换成int类型,可以使用mapToInt方法来实现

    public static void main(String[] args) {
        //Integer 占用的内存比int多很多,在Stream流操作中会自动装修和拆箱操作
        Integer arr[] ={1,2,3,4,6,7,8};
        Stream.of(arr).filter(x -> x > 0).forEach(System.out::println);
        //为了提高程序代码效率,可以先将流中Integer数据转为为int数据
        IntStream intStream = Stream.of(arr).mapToInt(Integer::intValue);
        intStream.forEach(System.out::println);
    }  

3.14、concat

如果有两个流,希望合并成为一个流,那么可以使用Stream接口防范concat

    public static void main(String[] args) {
        Stream<String> steam1=Stream.of("a","b","c");
        Stream<String> steam2=Stream.of("x","y","z");
        //通过concat方法将两个流合并成一个新的流
        Stream.concat(steam1,steam2).forEach(System.out::println);
    }  

3.15、综合案例

4.1、结果收集到集合中

    public static void main(String[] args) {
        List<String> list1 = Arrays.asList("迪丽热巴", "宋远桥", "苏星河", "老子",
                "庄子", "孙子", "洪七公");
        List<String> list2 = Arrays.asList("古力娜扎", "张无忌", "张三丰", "赵丽颖",
                "张二狗", "张天爱", "张三");
        Stream<String> stream1 = list1.stream().filter(s -> s.length() == 3).limit(3);
        Stream<String> stream2 =list2.stream().filter(s -> s.startsWith("张")).skip(2);
        Stream.concat(stream1,stream2)
                //.map(s -> new Person(s))
                .map(Person::new)
                .forEach(System.out::println);
    }

四、Stream结果手集

4.1、结果收集到集合中

    @Test
    public void test01(){
        //收集到list集合中
        List<String> list= Stream.of("a","b","c").collect(Collectors.toList());
        System.out.println(list);

        //收集到set集合中
        Set<String> set = Stream.of("aa","bb","cc","dd")
                .collect(Collectors.toSet());
        System.out.println(set);

        //如果需要获取的类型为具体实现
        ArrayList<String> arrayList = Stream.of("aaa","bbb","ccc")
                //.collect(Collectors.toCollection(() -> new ArrayList<>()));
                        .collect(Collectors.toCollection(ArrayList::new));
        System.out.println(arrayList);
    }

4.2、结构收集到数组中

Stream中提供了toArray方法来将结果放到一个数组中,返回值类型是Object[]。
如果我们要指定返回的类型,那么可以使用另一个重载的toArray(IntFunction f)方法。

    @Test
    public void test02(){
        //收集结果到数组中,数据类型是Object
        Object[] objects = Stream.of("aaa","bbb","ccc")
                .toArray();
        System.out.println(Arrays.toString(objects));

        //收集结构到数组中,数据类型是String
        String[] strings = Stream.of("aaa","bbb","ccc")
                .toArray(String[]::new);
        System.out.println(Arrays.toString(strings));
    }

4.3、对流中数据做聚合操作

当我们使用Stream流处理数据后,可以根据某个属性将数据分组

    @Test
    public void test03(){
        //获取年龄最大值
        List<Person> personList= Arrays.asList(new Person("张三",20),
                new Person("李四",25),
                new Person("王五",30),
                new Person("赵六",35));

        Optional<Person> maxAgePerson = personList.stream()
        //.collect(Collectors.maxBy(Comparator.comparingInt(Person::getAge)));
        .collect(Collectors.maxBy((p1,p2)->p1.getAge()-p2.getAge()));
        System.out.println("最大年龄: "+maxAgePerson.get());

        //获取年龄最小值
        Optional<Person> minAgePerson = personList.stream()
                .collect(Collectors.minBy((p1,p2)->p1.getAge()-p2.getAge()));
        System.out.println("最小年龄: "+minAgePerson.get());

        //求所有人的年龄之和
        Integer sumAge = personList.stream()
                .collect(Collectors.summingInt(Person::getAge));
        System.out.println("年龄总和:" + sumAge);

        //求所有人的年龄平均值
        Double avgAge = personList.stream()
                .collect(Collectors.averagingInt(Person::getAge));
        System.out.println("年龄的平均值:" + avgAge);

        //统计数量
        Long count = personList.stream().filter(p-> p.getAge() > 20)
                .collect(Collectors.counting());
        System.out.println("满足条件的记录数:" + count);
    }

4.4、对流中数据做分组操作

当我们使用Stream流处理数据后,可以根据某个属性将数据分组

    public void test04(){
        List<Person> personList= Arrays.asList(
                new Person("张三", 18, 175)
                , new Person("李四", 22, 177)
                , new Person("张三", 14, 165)
                , new Person("李四", 15, 166)
                , new Person("张三", 19, 182));
        //根据姓名对数据分组
        Map<String,List<Person>> map1= personList.stream()
                .collect(Collectors.groupingBy(Person::getName));
        map1.forEach((k,v)-> System.out.println("k=" + k +"\t"+ "v=" + v));
        System.out.println("-----------");
        Map<String, List<Person>> map2 = personList.stream()
                .collect(Collectors.groupingBy(p -> p.getAge() >= 18 ? "成年" : "未成年"));
        map2.forEach((k,v)-> System.out.println("k=" + k +"\t"+ "v=" + v));
    }

多级分组

    @Test
    public void test05(){
        List<Person> personList= Arrays.asList(
                new Person("张三", 16, 175)
                , new Person("李四", 22, 177)
                , new Person("张三", 14, 165)
                , new Person("李四", 15, 166)
                , new Person("张三", 19, 182));
        //先根据name分组,然后根据age(成年和未成年)分组
        Map<String,Map<Object,List<Person>>> map= personList.stream()
                .collect(Collectors.groupingBy(Person::getName,
                        Collectors.groupingBy(p-> p.getAge() >= 18 ? "成年" : "未成年")));
        map.forEach((k,v)->{
            System.out.println("k=" + k);
            v.forEach((kk,vv) -> System.out.println("\t"+"kk="+kk+"\tvv="+vv));
        });

4.5、对流中数据做分区操作

Collectors.partitioningBy会根据值是否为true,把集合中的数据分割为两个列表,一个true列表,一个
false列表

    @Test
    public void test06(){
        List<Person> personList= Arrays.asList(
                new Person("张三", 16, 175)
                , new Person("李四", 22, 177)
                , new Person("张三", 14, 165)
                , new Person("李四", 15, 166)
                , new Person("张三", 19, 182));
        Map<Boolean, List<Person>> map = personList.stream()
                .collect(Collectors.partitioningBy(p -> p.getAge() > 18));
        map.forEach((k,v)-> System.out.println(k+"\t" + v));
    }

4.6、对流中数据做拼接

Collectors.joining会根据指定的连接符,将所有的元素连接成一个字符串

    @Test
    public void test07(){
        List<Person> personList= Arrays.asList(
                new Person("张三", 18, 175)
                , new Person("李四", 22, 177)
                , new Person("张三", 14, 165)
                , new Person("李四", 15, 166)
                , new Person("张三", 19, 182));
        String s1 = personList.stream().map(Person::getName)
                .collect(Collectors.joining());
        // 张三李四张三李四张三
        System.out.println(s1);
        String s2 = personList.stream().map(Person::getName)
                .collect(Collectors.joining("_"));
        // 张三_李四_张三_李四_张三
        System.out.println(s2);
        String s3 = personList.stream().map(Person::getName)
                .collect(Collectors.joining("_", "###", "$$$"));
        // ###张三_李四_张三_李四_张三$$$
        System.out.println(s3);
    }

五、并行Stream流

5.1、串行的Stream流

我们前面使用的Stream流都是串行,也就是在一个线程上面执行。

    @Test
    public void test01(){
        long count = Stream.of(5,6,7,4,2,1,9)
                .filter(s ->{
                    System.out.println(Thread.currentThread().getName() + ":" + s);
                    return s > 3;
                }).count();
        System.out.println(count);
    }

5.2、并行流

parallelStream其实就是一个并行执行的流,它通过默认的ForkJoinPool,可以提高多线程任务的速
度。

5.2.1、获取并行流

    @Test
    public void test02(){
        List<Integer> list=new ArrayList<>();
        //通过list接口直接获取并行流
        Stream<Integer> stram=list.parallelStream();
        //将已有的串行流转换为并行流
        Stream<Integer> parallel=Stream.of(1,2,3).parallel();
    }

5.2.3、并行流操作

    @Test
    public void test03(){
        long count = Stream.of(5,6,7,4,2,1,9)
                .parallel()
                .filter(s ->{
                    System.out.println(Thread.currentThread().getName() + ":" + s);
                    return s > 3;
                }).count();
        System.out.println(count);
    }

5.3、并行流和串行流对比

我们通过for循环,串行Stream流,并行Stream流来对500000000亿个数字求和。来看消耗时间

public class StresmTest24 {

    private static long times=500000000;

    private long start;

    @Before
    public void before(){
        start=System.currentTimeMillis();
    }

    @After
    public void end(){
        long end=System.currentTimeMillis();
        System.out.println("消耗时间:"+(end - start));
    }

    @Test
    public void test01(){
        System.out.println("普通for循坏:");
        long res= 0;
        for (int i = 0;i<times;i++){
            res+=1;
        }
    }

    @Test
    public void test02(){
        System.out.println("串行流:serialStream");
        LongStream.rangeClosed(0,times).reduce(0,Long::sum);
    }

    @Test
    public void test03(){
        LongStream.rangeClosed(0,times)
                .parallel().reduce(0,Long::sum);
    }


}

5.4、线程安全

在多线程的处理下,肯定会出现数据安全问题。如下:

    @Test
    public void test01(){
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            list.add(i);
        }
        System.out.println(list.size());
        List<Integer> listNew =new ArrayList<>();
        list.parallelStream()
                .forEach(listNew::add);
        System.out.println(listNew.size());
    }

这个会抛出异常

	java.lang.ArrayIndexOutOfBoundsException

针对这个问题,我们的解决方案有哪些呢?

  1. 加同步锁
  2. 使用线程安全的容器
  3. 通过Stream中的toArray/collect操作
    实现:
@Test
    public void test02(){
        List<Integer> listNew = new ArrayList<>();
        Object obj = new Object();
        IntStream.rangeClosed(1,1000)
                .parallel()
                .forEach(i->{
                    synchronized (obj){
                        listNew.add(i);
                    }
                });
        System.out.println(listNew.size());
    }

    @Test
    public void test03(){
        Vector v = new Vector();
        Object obj = new Object();
        IntStream.rangeClosed(1,1000)
                .parallel()
                .forEach(i->{
                    synchronized (obj){
                        v.add(i);
                    }
                });
        System.out.println(v.size());
    }

    @Test
    public void test04(){
        List<Integer> listNew = new ArrayList<>();
        // 将线程不安全的容器包装为线程安全的容器
        List<Integer> synchronizedList = Collections.synchronizedList(listNew);
        Object obj = new Object();
        IntStream.rangeClosed(1,1000)
                .parallel()
                .forEach(i->{
                    synchronizedList.add(i);
                });
        System.out.println(synchronizedList.size());
    }

    @Test
    public void test05(){
        List<Integer> listNew = new ArrayList<>();
        Object obj = new Object();
        List<Integer> list = IntStream.rangeClosed(1, 1000)
                .parallel()
                .boxed()
                .collect(Collectors.toList());
        System.out.println(list.size());
    }

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

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

相关文章

vue3表格使用Switch 开关

本示例基于vue3 element-plus 注&#xff1a;表格数据返回状态值为0、1。开关使用 v-model"scope.row.state 0" 会报错 故需要对写法做些修改&#xff0c;效果图如下 <el-table-column prop"state" label"入学状态" width"180" …

【11408学习记录】考研写作双核引擎:感谢信+建议信复合结构高分模板(附16年真题精讲)

感谢信建议信 英语写作2016年考研英语&#xff08;二&#xff09;真题小作文题目分析写作思路第一段第二段锦囊妙句9&#xff1a;锦囊妙句12&#xff1a;锦囊妙句13&#xff1a;锦囊妙句18&#xff1a; 第三段 妙句成文 每日一句词汇第一步&#xff1a;找谓语第二步&#xff1a…

一套个人知识储备库构建方案

写文章的初心是做知识沉淀。 好记性不如烂笔头&#xff0c;将阶段性的经验总结成文章&#xff0c;下次遇到相同的问题时&#xff0c;查起来比再次去搜集资料快得多。 然而&#xff0c;当文章越来越多时&#xff0c;有一个问题逐渐开始变得“严峻”起来。 比如&#xff0c;我…

行李箱检测数据集VOC+YOLO格式2083张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;2083 标注数量(xml文件个数)&#xff1a;2083 标注数量(txt文件个数)&#xff1a;2083 …

实践提炼,EtherNet/IP转PROFINET网关实现乳企数字化工厂增效

乳企数字化工厂的核心技术应用 1. 智能质检&#xff1a;机器视觉协议网关的协同 液态奶包装线&#xff08;利乐罐装&#xff09;的漏码检测生产线&#xff0c;其高速产线&#xff08;20,000包/小时&#xff09;需实时识别微小缺陷&#xff0c;但视觉系统&#xff08;康耐视Ca…

从以物换物到DeFi:交易的演变与Arbitrum的DeFi生态

交易的本质&#xff1a;从以物换物到现代金融 交易是人类社会经济活动的核心&#xff0c;是通过交换资源&#xff08;如货物、服务或货币&#xff09;满足各方需求的行为。其本质是价值交换&#xff0c;旨在实现资源的优化配置。交易的历史可以追溯到人类文明的起源&#xff0…

分类场景数据集大全「包含数据标注+训练脚本」 (持续原地更新)

一、作者介绍&#xff1a;六年算法开发经验、AI 算法经理、阿里云专家博主。擅长&#xff1a;检测、分割、理解、大模型 等算法训练与推理部署任务。 二、数据集介绍&#xff1a; 质量高&#xff1a;高质量图片、高质量标注数据&#xff0c;吐血标注、整理&#xff0c;可以作为…

Web后端开发(SpringBootWeb、HTTP、Tomcat快速入门)

目录 SpringBootWeb入门 Spring 需求&#xff1a; 步骤&#xff1a; HTTP协议&#xff1a; 概述&#xff1a; 请求协议&#xff1a; 响应协议&#xff1a; 协议解析&#xff1a; Web服务器-Tomcat&#xff1a; 简介&#xff1a; 基本使用&#xff1a; SpringBootWeb…

android binder(四)binder驱动详解2

二、情景分析 1、ServiceManager 启动过程 2. 服务注册 服务注册过程(addService)核心功能&#xff1a;在服务所在进程创建binder_node&#xff0c;在servicemanager进程创建binder_ref。其中binder_ref的desc在同一个进程内是唯一的&#xff1a; 每个进程binder_proc所记录的…

4G无线网络转串口模块 DTU-1101

4G无线网络转串口模块概述 4G无线网络转串口模块是一种工业通信设备&#xff0c;通过4G网络将串口&#xff08;如RS232/RS485&#xff09;设备接入互联网&#xff0c;实现远程数据传输与控制。适用于物联网&#xff08;IoT&#xff09;、工业自动化、远程监控等场景。 核心功能…

机器学习方法实现数独矩阵识别器

目录 导包 工具函数构建说明 1. 基础图像处理工具 2. 图像预处理模块 3. 数独轮廓检测与定位 4. 网格划分与单元格提取 5. 数字特征提取 6. 多网格处理流程 数据流分析 核心算法详解 核心机器视觉方法 1. 透视变换校正算法 2. 数字区域提取算法 3. 多网格检测算法…

【Vmwrae】快速安装windows虚拟机

前言 虚拟机是我们在使用电脑进行开发或者平常工作时经常使用到的工具 它可以自定义各种硬件&#xff0c;运行各种不同的系统&#xff0c;且无论发生什么都不会影响到实体机。 教程主要讲了如何在零基础的情况下快速安装一台虚拟机。 下载安装 VMware Workstation Pro17 …

多线程3(Thread)

wait / notify 线程调度是随机的&#xff0c;但是我们可以使用wait/notify进行规划。 join是控制线程结束顺序&#xff0c;而wait/notify是控制详细的代码块&#xff0c;例如&#xff1a; 线程1执行完一段代码&#xff0c;让线程2继续执行&#xff0c;此时线程2就通过wait进…

附加模块--Qt Shader Tools功能及架构解析

Qt 6.0 引入了全新的 Shader Tools 模块&#xff0c;为着色器管理提供了现代化、跨平台的解决方案。 一、主要功能 核心功能 跨平台着色器编译 支持 GLSL、HLSL 和 MetalSL 着色器语言 可在运行时或构建时进行着色器编译 自动处理不同图形API的着色器变体 SPIR-V 支持 能…

网络编程(计算机网络基础)

思维导图 认识网络 1.网络发展史 ARPnetA(阿帕网)->internet(因特网)->移动互联网->物联网 2.局域网与广域网 局域网 概念&#xff1a;的缩写是LAN&#xff08;local area network&#xff09;&#xff0c;顾名思义&#xff0c;是个本地的网络&#xff0c;只能实现…

在React 中安装和配置 shadcn/ui

1. 创建 React 项目 pnpm create vitelatest .选择模板&#xff1a;React TypeScript安装依赖&#xff1a;pnpm install2. 添加 Tailwind CSS pnpm add -D tailwindcss postcss autoprefixer修改 src/index.css 内容&#xff1a; import "tailwindcss";3. 配置 T…

WINUI——WINUI开发中谨慎使用x:Bind

原因——为什么需要谨慎使用x:Bind&#xff1f; 在实际开发中发现&#xff0c;使用它会导致VM回收不及时&#xff0c;可能导致内存泄漏。 那为何要在项目中使用它呢&#xff1f; 因为&#xff1a;{x&#xff1a;Bind} 标记扩展&#xff08;Windows 10 的新增功能&#xff09;…

MSYS2 环境配置与 Python 项目依赖管理笔记

#工作记录 MSYS2 环境配置 安装和更新 MSYS2 初始安装 下载并安装 MSYS2&#xff1a; 访问 MSYS2 官方网站 并下载安装包。 按照安装向导完成安装。 更新 MSYS2&#xff1a; 打开 MSYS2 终端&#xff08;MSYS2 MINGW64&#xff09;。 更新包数据库和核心系统包&#xff1…

华为云Flexus+DeepSeek征文|华为云一键部署知识库搜索增强版Dify平台,构建智能聊天助手实战指南

目录 前言 1 架构描述 2 资源栈创建流程详解 2.1 选择部署模板 2.2 参数配置内容 2.3 资源栈设置选项 2.4 配置确认与执行方式 3 部署过程与控制台反馈 3.1 实时资源监控 3.2 资源详情与访问路径 3.3 模板与事件管理 4 知识库构建流程 4.1 数据导入操作 4.2 文本…

分形几何在医学可视化中的应用:从理论到Python实战

分形几何在医学可视化中的应用&#xff1a;从理论到Python实战 前言 分形几何作为描述自然界复杂结构的数学工具&#xff0c;正通过其自相似性和分数维度特性&#xff0c;革新医学影像分析领域。本文系统阐述分形几何在医学影像中的创新应用&#xff0c;涵盖从图像预处理、分…