Java进阶-Lambda

Java进阶-Lambda

  • 前言
  • Lambda表达式
    • 什么是Lambda表达式
    • 初识Lambda表达式
      • Lambda表达式的简单使用
      • Lambda表达式格式分析
        • 与传统接口方法实现的比较
    • 理解Lambda表达式
      • 函数式编程
        • 非纯函数实例
        • 纯函数示例
        • 函数式编程在Lambda表达式中的体现
      • 闭包
        • 闭包与Lambda表达式的示例
      • 类型推导-匿名内部类
        • 匿名内部类与Lambda表达式的示例
    • 常规使用Lambda表达式的场景
      • 函数式接口的实现
      • 并发编程
      • 排序和比较
      • 集合与流
        • 流的前置了解
        • 集合、流以及Lambda的简单结合
        • 并行流
    • 其他
      • Lambda表达式中的双冒号( :: )
      • 方法引用的几种形式:
      • 使用场景:
      • 示例:
  • 写在最后

前言

最近都没什么时间给自己充电,不过想了想还是要继续学习的,所以想着开始写一期博客关于:以前用过但是又没学懂的知识,可以称之为薛定谔的知识,就是我看得懂,也会用,但是为什么要这么用,什么时候这么用?我不知道

这一节的第一讲就从最近用的比较多的Lambda表达式开始吧,本文仅当为入门学习,如有遗漏还请指出。

Lambda表达式

什么是Lambda表达式

Lambda表达式是自Java 8 版本引入的一个重要特性,也可以说是最重要的一个特性,它提供了一种更简洁、更直接的方式来表示功能接口(即只包含一个抽象方法的接口)的匿名实现。Lambda表达式允许你以一种更接近数学中函数概念的方式编写代码,使得Java编程更加灵活和表达力更强。

注意上面的:它提供了一种更简洁、更直接的方式来表示功能接口(即只包含一个抽象方法的接口)的匿名实现(省略了方法名的实现)
这一句可以简单缩短为:提供了只有一个方法接口的匿名实现方式,首先它是接口的实现方式,什么实现方式呢?匿名实现。

还是没看太懂?没事,我们接着往下看

初识Lambda表达式

我们先看一个Lambda表达式的简单使用,先认识认识它们,然后再慢慢摸索。

下面我们来看一个常见的Lambda表达式的使用,以及它们的格式。

Lambda表达式的简单使用

以下是一个使用Lambda表达式实现自定义接口的示例
首先创建一个只有一个抽象方法的的接口

@FunctionalInterface//用于表示这是一个函数式接口的注解 即该接口中只有一个方法 关于函数后续会提到
public interface DemoLambdaInterface {
      int operate(int a , int b);//两个数的简单操作
}

那我们再来看看如何使用Lambda表达式实现该接口

public class Test {
    public static void main(String[] args) {
        //接口中方法的匿名实现
        DemoLambdaInterface demoLambdaInterface = (a , b) -> a + b;
        //调用跟常规接口方法调用没有区别
        System.out.println("使用Lambda表达式匿名实现的接口调用结果为:" + demoLambdaInterface.operate(1, 2));
    }
}

Lambda表达式格式分析

相信大家对于上述的代码,还是看不懂,你确定这一段是Java代码?(a , b) -> a + b;

其实将这段代码:DemoLambdaInterface demoLambdaInterface = (a , b) -> a + b;补全你就知道了

补全之后就是以下这样的

        //接口中方法的匿名实现
        DemoLambdaInterface demoLambdaInterface = (a , b) -> {
            return  a + b;
        };

结合我们接口中的定义

@FunctionalInterface//用于表示这是一个函数式接口的注解 即该接口中只有一个方法 关于函数后续会提到
public interface DemoLambdaInterface {
      int operate(int a , int b);//两个数的简单操作
}

看出来什么没有,没错就是那个! 接口的实现嘛,不过我们一般写实现都是带了方法名的

 int operate(int a , int b) {
	return a + b;
 }

现在我们来分析上述代码,
(a , b)表示接口方法的入参,但是没有类型,比如int ,String

->是一个特殊的语法符号,被称为箭头操作符或者Lambda操作符起到参数与方法体分割的作用

其后的{}中的内容就是方法体的具体实现内容了。

而在Lambda表达式中单行代码是可以省略{}和return,也就成了上面的:

DemoLambdaInterface demoLambdaInterface = (a , b) -> a + b;

如果方法的参数为空,那括号里可以什么都不写了

与传统接口方法实现的比较

如果按照常规的方法,来实现接口方法,我们一般怎么写?
首先肯定是创建一个实现类DemoLambdaInterfaceImpl:

public class DemoLambdaInterfaceImpl implements DemoLambdaInterface {
	 //实现接口方法
	 int operate(int a , int b) {
		return a + b;
	 }
}

然后使用的时候再通过创建实现类对象去调用:

	DemoLambdaInterface dli = new DemoLambdaInterfaceImpl();
	dli.operate(1 , 2);

与上面的Lambda表达式相比,谁简洁一目了然。

理解Lambda表达式

我们先来做点课前准备工作,将以下几部分学习完再理解Lambda表达式就很简单了。以下几部分同样是Lambda表达式的重要特性。

函数式编程

Lambda表达式可以说是实现函数式编程的一个重要工具。那么什么是函数式编程呢?

函数式编程是一种编程范式,强调程序构建在不可变数据和纯函数之上

不可变数据好理解,关键是后面的纯函数什么?

纯函数是指对于相同的输入总是产生相同的输出,并且没有‘副作用’,这里的副作用是:不改变外部状态或依赖外部状态

注意这两点:相同的输入总有相同的输出不改变外部状态或依赖外部状态

要快速理解这两句话,我们要从相反的角度看:相同的输入得到不同的输出,改变外部状态或者依赖外部状态的就不是函数式编程

非纯函数实例

来看以下非纯函数的代码

public class Test {
    static int gamePeopleCount = 0;
    public static void main(String[] args) {
        String demoStr = "小游戏玩家: ";
        int a = addGamePeopleCount("小明");
        System.out.println("当前游戏人数:" + a);
        addGame(demoStr , "小明");
    }

    public static int  addGamePeopleCount(String name) {
        System.out.println(name + " 加入了游戏。");
        //每次返回的结果不一样
        gamePeopleCount+=1;
        return gamePeopleCount;
    }

    public static void addGame(String demoStr , String name) {
        //修改了demoStr的值 也就改变了外部状态
        demoStr = demoStr +" "+ name;
        System.out.println(demoStr);
    }
}
纯函数示例

再看一个纯函数的示例

public int add(int a , int b) {
	return a + b;
}

在纯函数中,很明显可以看出上述两个特征:相同的输入总有相同的输出不改变外部状态或依赖外部状态

函数式编程在Lambda表达式中的体现

上面的代码就是

  		//接口中方法的匿名实现
        DemoLambdaInterface demoLambdaInterface = (a , b) -> a + b;

闭包

很多人说:Lambda表达式也可称为闭包。那什么是闭包(仅仅从Lambda表达式出发)?

闭包是一个函数,它能够访问并记住其自身定义时所在作用域中的变量,甚至延长变量的生命周期。
也就是说闭包是一个能记住其自身定义时所在作用域中变量的函数

说人话就是,一个闭包可以调用到上下文中的局部变量。再通俗一点就是:。。。。还是代码说事吧

闭包与Lambda表达式的示例
@FunctionalInterface
public interface DemoLambdaInterface {
    void sayHello();
}

这里的@FunctionalInterface 注解并不是强制要求的,它是一个标记,用于指示接口是设计为一个函数式接口只有一个抽象方法)。

public class Test {
    public static void main(String[] args) {
        //Lambda表达式的简单使用
        String localVariable = "这是局部变量,并没有传递给方法 ";//如果一个局部变量没有通过参数传递给方法,一般是无法使用的
        //Lambda表达式
        DemoLambdaInterface demoLambdaInterface = () -> {
            System.out.println(localVariable + "hello");
        };
        //在这里调用
        demoLambdaInterface.sayHello();
    }
}

在上述方法中,可以看到localVariable没有作为方法参数传递给sayHello方法,但是demoLambdaInterface对象在这里还是可以使用到localVariable变量,这就是我们上述讲的:一个闭包可以调用到上下文中的局部变量,也就是你的函数可以使用到当前上下文的局部变量

类型推导-匿名内部类

类型推导作为Lambda表达式的一大特性之一,怎么能没有呢?我们以匿名内部类为例子说明。

匿名内部类(Anonymous Inner Class)是Java中一种特殊的内部类(如果这个都不知道就真的需要好好补课了),它没有明确的类名。匿名内部类通常用于实现接口或继承其他类,并且只在创建它的代码块中直接使用,而不需要显式地为其定义类名。

这个应该或多或少都接触过,比如我们最常见的Thread的使用:

	   Thread myThread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("我是匿名内部类");
            }
        });

        myThread.start();

这其中的构造方法:

    public Thread(Runnable target) {
        this(null, target, "Thread-" + nextThreadNum(), 0);
    }

这里的方法参数为Runnable的对象,但其实这里的Runnable是一个接口

@FunctionalInterface
public interface Runnable {
    /**
    	一些注释
     */
    public abstract void run();
}

对于一个接口对象,如果你要按照正常的写法的话,要么再写一个实现类要么使用其子类,然后使用实现类去传参给Thread的构造方法

是不是听着就很麻烦,但现在使用匿名内部类就可以在构造时直接自己实现这个类,而不用创建新的实现类。就是上面的

	   Thread myThread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("我是匿名内部类");
            }
        });

        myThread.start();

但是使用Lambda表达式更为直接也更为简洁

匿名内部类与Lambda表达式的示例

在以下Lambda表达式中,Lambda表达式通过类型推导,返回的是一个接口的实现

		Thread t = new Thread(() -> {
            System.out.println("我是Lambda表达式");
        });
        
        t.start();

当你将Lambda表达式赋值给一个函数式接口类型的变量时,Java编译器会自动进行类型推导。在这个例子中,编译器知道t是一个Thread类型的变量,它的构造函数接受一个Runnable类型的参数。因此,编译器将Lambda表达式推断为实现了Runnable接口的匿名类的一个实例

优点嘛,简洁!!!简洁!!!还是T~~~M的简洁!!!

常规使用Lambda表达式的场景

好了,说了那么多,我们再来看看,日常使用Lambda表达式的场景吧

函数式接口的实现

就是我们第一个例子中的,带有@FunctionalInterface注解的接口叫做函数式接口,都是可以使用Lambda表达式实现的。这样的接口中只有一个抽象方法,如上面提到的Runnable接口,这就是一个很标准的

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

但有时候,一个拥有很多的方法的接口,依然有@FunctionalInterface注解,也可以使用Lambda表达式实现,比如上面也说过的比较器Comparator

@FunctionalInterface
public interface Comparator<T> {
	 int compare(T o1, T o2);
	//其他方法
	
}

这是因为它只有一个自己的抽象方法。其他的方法要么不是抽象方法,要么就是继承来的,都不被计算在内。比如以下就只有一个compare(T , T)的抽象方法
在这里插入图片描述
如何实现,我们后续会以这个接口举例

并发编程

这里主要是使用Lambda表达式来进行线程池的创建,Lambda表达式允许以一种简洁、声明式的方式编写功能逻辑,减少了传统的匿名类或显式方法定义的冗长。

如以下部分

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class LambdaThreadPoolExample {

    public static void main(String[] args) {
        // 创建一个固定大小的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        // 提交任务到线程池,使用Lambda表达式定义Runnable任务
        for (int i = 0; i < 10; i++) {
            int taskId = i;
            executorService.submit(() -> {//Lambda表达式替代以前的匿名内部类
                System.out.println("Task ID " + taskId + " is running by " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000); // 模拟耗时操作
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    System.out.println("Thread interrupted.");
                }
            });
        }

        // 关闭线程池,不再接受新任务,等待所有已提交的任务完成
        executorService.shutdown();
        while (!executorService.isTerminated()) {
            // 等待直到所有任务完成
        }
        System.out.println("All tasks completed.");
    }
}

排序和比较

这个比较器(Comparator)接口大家应该很常用,尤其是我需要按照对象某个属性进行排序的时候

@FunctionalInterface//可以看出来是一个函数式接口
public interface Comparator<T> {
	  int compare(T o1, T o2);//大于返回正数 小于返回负数 等于返回0
	  //其他接口
}

以及StringcompareTo方法

现在我们来看看如何使用Lambda表达式来快速对集合中的元素排序(常规的就不讲了),我们这里创建一个简单的实体类Student为例子

@Data//get-set方法的生成
@AllArgsConstructor//全参构造函数
public class Student {
    int id;
    String name;
    int age;
}

具体实现

public class SortLambdaTest {
    public static void main(String[] args) {
        List<Student> list = new ArrayList<>();
        list.add(new Student(2 , "ZhangSan" , 15));
        list.add(new Student(1 , "LiSi" , 13));
        list.add(new Student(4 , "WangWu" , 26));
        list.add(new Student(3 , "ZhaoLiu" , 18));
        //使用Lambda表达式按照不同的对象属性排序
        System.out.println("================按照ID排序========================");
        //按照id排序
        Collections.sort(list , (stu1 , stu2) -> stu1.getId() - stu2.getId());
        //使用Lambda表达式遍历输出输出
        list.forEach(stu -> System.out.println(stu.toString()));
        System.out.println("=================================================");

        System.out.println("==================按照NAME排序=====================");
        //按照名字排序
        Collections.sort(list , (stu1 , stu2) -> stu1.getName().compareTo(stu2.getName()));//使用compareTo方法
        list.forEach(stu -> System.out.println(stu.toString()));
        System.out.println("=================================================");

        //课后作业 按照年龄排序
    }
}

从输出结果中可以确定自己写的有无正确排序
在这里插入图片描述

这个其实很常用,比如我们在调用外部接口时,对方返回的数据默认是以主键排序,但其实我们本地的逻辑是要使用Name排序或者手机号排序,这样的话是需要我们再进行一次排序。
与其给每一个实体类加一个实现比较器接口,再实现比较方法,Lambda表达式的实现更为简洁。

集合与流

在这一章之前,我们需要了解以下什么是什么是流,流有哪些特点方面

流的前置了解

在 Java 中,流 (Stream)Java 8 引入的一种新的抽象,用于对集合(如列表、集合等)进行复杂的数据处理操作。流提供了一种声明式的方式来处理数据,使得代码更加简洁和易读。
在这里插入图片描述

流操作主要分为两种类型:中间操作 (intermediate operations) 和终端操作 (terminal operations)

中间操作指的是,该方法会返回一个新的流,如以下图中的方法。返回值都是流或者其子类
在这里插入图片描述

终端操作是指流的执行,并且返回结果。(中间操作并不会执行以及返回结果,可以理解为把要做的操作记录下来)
在这里插入图片描述

其实可以简单理解为:返回值不是Stream的都是终端方法
这里列出常用中间操作与终端操作的方法

中间操作 (Intermediate Operations)

  1. filter(Predicate<? super T> predicate):筛选符合条件的元素,生成一个包含满足条件元素的新流。(比如获取流中所有带“三文鱼”字符的元素)
  2. map(Function<? super T, ? extends R> mapper):将流中的每个元素转换为另一种形式,生成一个包含转换后元素的新流。(就是来做映射)
  3. flatMap(Function<? super T, ? extends Stream<? extends R>> mapper):将流中的每个元素转换为一个流,然后将这些流合并成一个新的流。(同上)
  4. sorted(Comparator<? super T> comparator):根据提供的比较器对流中的元素进行排序,生成一个排序后的新流。(排序)
  5. distinct():去重

终端操作 (Terminal Operations)

  1. collect(Collector<? super T, A, R> collector):转换成集合
  2. forEach(Consumer<? super T> action):遍历流对所有元素进行操作,比如+1
  3. count():计算总数量并返回
  4. anyMatch(Predicate<? super T> predicate):检查流中的任意一个元素是否匹配给定的条件
  5. findFirst():返回流中的第一个元素的 Optional 对象,如果流为空则返回空的 Optional

其大致特点如下

  1. 声明式编程:流 API 允许你使用声明式的方法来处理数据,而不是使用传统的命令式方法。(声明式编程指的是关注于描述数据的操作,而非具体的执行过程。比如你只需要告诉流去执行过滤(filter)、映射(映射)、返回集合(collect)等操作,而不需要关心怎么实现。)
  2. 链式操作:流操作可以链式调用,每个中间操作都会返回一个新的流,这里其实很好理解,因为每个操作返回的是新的当前对象,那么自然可以继续调用当前对象所拥有的方法。
  3. 惰性求值:流的中间操作是惰性的,只有在终端操作调用时才会执行,也就是你挂了一串鞭炮,没有点燃引线之前,你的鞭炮不会响。
  4. 不可变性:流操作不会修改原始数据,而是返回一个新的流。
集合、流以及Lambda的简单结合

说了那么多,来点代码理解下

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;


public class StreamWithLambda {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("coco", "alice", "bob" , "joker","worker" ,"bob");
        //使用Lambda表达式过滤出包含o的所有元素
       List<String> oList = list.stream()
                .filter(s -> s.contains("o"))//使用Lambda表达式来定义过滤操作  中间操作
                .collect(Collectors.toList());//中间操作
        System.out.println("所有包含o的数据");
        //同样使用流遍历输出元素
        oList.stream()
                .forEach(str -> System.out.println(str));//终端操作
        System.out.println("=======================================");

        System.out.println("链式操作后的数据");
        //链式编程
        list.stream()
                .filter(s -> s.contains("o"))//所有包含o的数据 中间操作
                .sorted()//默认排序 中间操作
                .distinct()//去重 中间操作
                .forEach(str -> System.out.println(str));//终端操作 遍历
        System.out.println("=======================================");

        //原来的数据是不会变的
        System.out.println("上述操作后,原来数据为:");
        list.forEach(s -> System.out.println(s));
        System.out.println("=======================================");

        //判断时是否包含coco 使用anyMatch去判断是否包含 allMatch是指所有元素满足的条件
        if (list.stream().anyMatch(s -> s.equals("coco"))) {
            System.out.println("字符中包含coco");
        } else {
            System.out.println("没有coco");
        }
    }

输出如下

所有包含o的数据
coco
bob
joker
worker
bob
=======================================
链式操作后的数据
bob
coco
joker
worker
=======================================
上述操作后,原来数据为:
coco
alice
bob
joker
worker
bob
=======================================
字符中包含coco

可以看到如果你对于一个你拿到的数据不满意,随时可以使用Stream以及Lambda表达式去得到你需要的数据。无论是排序,映射,过滤,去重以及别的操作,都非常简便快捷。

并行流

当然了,Stream同样可以多线程操作,这也是比较重要的一部分:并行流(通过parallelStream()方法得到)

值得注意的并行流是指多个线程去处理你的中间操作,以提高效率,但是并不保证线程安全

对于敏感数据可以考虑以下操作避免并行流带来的线程不安全

确保并行流处理时的线程安全,可以通过以下几种方式来实现:

  1. 使用线程安全的数据结构:使用线程安全的数据结构,比如ConcurrentHashMapCopyOnWriteArrayList等,因为它们内部已经处理好了线程同步问题。

  2. 无副作用的函数:确保你在流操作中使用的Lambda表达式或函数是无副作用的,即它们不改变外部状态,只依赖于输入值产生输出值。

  3. 同步访问共享资源:如果确实需要在Lambda表达式中修改共享资源,需要适当同步。可以考虑使用synchronized块或方法,或者使用其他同步工具类比如,如ReentrantLock(可重入锁)

  4. 原子变量与CAS操作:对于计数、累加等操作,可以使用AtomicInteger、AtomicLong等原子类

  5. 局部变量与ThreadLocal:尽可能使用局部变量,或者在必要时使用ThreadLocal存储线程特有的数据

上述方法可以有效确保并行流处理时的数据一致性与线程安全。

以下是一个简单使用并行流的例子:

import java.util.Arrays;  
import java.util.List;  
import java.util.stream.Collectors;  
  
public class ParallelStreamTest {  
  
    public static void main(String[] args) {  
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        int sum = numbers.stream().mapToInt(n -> n * n).sum();
        System.out.println("所有平方和: " + sum);
    }  
}

其他

Lambda表达式中的双冒号( :: )

在Java中,Lambda表达式的::操作符被称为方法引用(Method Reference),它是Lambda表达式的另一种更简洁的写法,用于引用已有方法。方法引用允许你直接引用现有类或对象的方法,而不需要显式定义Lambda表达式体。这种方法引用的语法看起来像是类名或对象实例后面跟着两个冒号,然后是方法名。

方法引用的几种形式:

  1. 静态方法引用ClassName::staticMethodName

    • 当你需要引用一个静态方法时使用。例如,Integer::parseInt引用了Integer.parseInt(String)静态方法。
  2. 特定对象的实例方法引用instance::methodName

    • 如果你有一个具体的对象,并想引用它的实例方法,可以这样做。例如,对于一个特定的String对象strstr::length引用了str.length()方法。
  3. 任意对象的实例方法引用ClassName::methodName

    • 当引用一个所有实例都有的方法(非静态方法)时,可以使用这种方式。例如,String::length可以用来代替Lambda表达式(s) -> s.length()
  4. 构造器引用ClassName::new

    • 构造器引用用于创建对象的新实例,例如,ArrayList::new可以用来创建一个新的ArrayList实例。

使用场景:

  • 简化Lambda表达式:当你发现Lambda表达式做的事情仅仅是调用一个已存在的方法时,可以考虑使用方法引用来替代,使代码更简洁。

  • 集合操作:在处理集合时,如使用sortmapfilter等操作时,方法引用可以简化对元素的操作逻辑。

  • 函数式接口:作为函数式接口(如FunctionConsumerPredicate等)的实现时,如果符合方法引用的条件,优先考虑使用方法引用。

  • 并行流:在并行流中,方法引用同样可以提高代码的可读性和性能,尤其是在不需要维护额外状态的并行处理场景下。

示例:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// 使用Lambda表达式
names.sort((a, b) -> a.compareTo(b));

// 使用方法引用简化
names.sort(String::compareTo);

在这个例子中,String::compareTo就是方法引用,它直接引用了String类的compareTo方法,代替了Lambda表达式(a, b) -> a.compareTo(b),使得代码更加简洁明了。

写在最后

拖来拖去,写了大半个月,才写完,有的部分也还没讲清楚,Lambda表达式作为Java8最核心的特性,涉及的方方面面实在是太多了,有的部分我也没有深入的接触到,具体使用的场景也不多,此文也仅仅当给各位作为一个入门的学习。

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

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

相关文章

【D3.js in Action 3 精译】1.2.2 可缩放矢量图形(一)

译注 由于 1.2.2 小节介绍 SVG 的篇幅过多&#xff0c;为了方便查阅&#xff0c;后续将分多个小节依次进行翻译。为了确保整个 1.2.2 小节的完整性&#xff0c;特意将上一篇包含的 SVG 小节的内容整理出来重新编排。敬请留意。 1.2.2 SVG - 可缩放矢量图形 可伸缩矢量图形&…

802.11漫游流程简单解析与笔记_Part2_02_wpa_supplicant、cfg80211、nl80211内核与驱动的关系

wpa、cfg80211、nl80211内核与驱动的关系示意图如下&#xff1a; nl80211和cfg80211都是内核定义的标准接口&#xff0c;目的是规范驱动和应用的统一调用&#xff0c;wpa中常出现nl80211就是通过内核的nl80211接口调用对应cfg80211的部分&#xff0c;进而控制驱动收发数据或切换…

实现高效写入:Schemaless 写入性能优化指南

物联网应用常常需要收集大量的数据&#xff0c;用以支持智能控制、业务分析和设备监控等功能。然而&#xff0c;应用逻辑的更新或硬件的调整可能会导致数据采集项频繁变化&#xff0c;这是时序数据库&#xff08;Time Series Database&#xff0c;TSDB&#xff09;面临的一大挑…

排序算法之java语言实现

零、说在前面 近期打算复习java的几种排序算法&#xff0c;我会将这些排序算法的实现代码、个人心得、时间复杂度分析&#xff0c;算法间的对比做成一个系列帖子&#xff0c;这里作为那些帖子的汇总而存在。 这个系列的框架会包含&#xff1a;概念、实现、时间空间复杂度…

50、基于NARX神经网络的磁悬浮建模(matlab)

1、NARX神经网络简介 NARX&#xff08;非线性自回归外部输入&#xff09;神经网络是一种用于非线性建模和预测的神经网络结构。与传统的自回归模型不同&#xff0c;NARX网络可以接收外部输入来影响输出结果&#xff0c;从而更好地捕捉系统的复杂性和非线性特征。 NARX神经网络…

为什么计算机中的无线网络被称为“Wi-Fi”?

在当今信息化社会中&#xff0c;无线网络已经成为我们生活中不可或缺的一部分。无论是家庭、办公室还是公共场所&#xff0c;我们都能享受到便捷的无线互联网连接。而当我们谈及无线网络时&#xff0c;一个经常听到的术语就是“Wi-Fi”。那么&#xff0c;为什么计算机中的无线网…

植物大战僵尸杂交版v2.1最新整合版,附PC端+安卓端+iOS端安装包+修改器+安装教程!

嘿&#xff0c;大家好&#xff0c;我是阿星&#xff0c;今天要跟大家聊聊一款游戏&#xff0c;它不是那种让人眼花缭乱的大制作&#xff0c;也不是那种能让人回味无穷的艺术作品&#xff0c;但它在阿星心里&#xff0c;绝对是神作中的佼佼者。没错&#xff0c;它就是《植物大战…

【windows】win11系统跳过联网和微软账户登录,实现本地账户登录

问题原因&#xff1a;现在市面上销售的品牌笔记本和台式机基本上都预装了正版的Windows S11家族中文版操作系统&#xff0c;联网后系统会自动激活。在win11的版本中&#xff0c;隐藏了关闭跳过连接网络的按钮&#xff0c;默认强制需要注册微软账户登录才能正常使用。 一、跳过…

动态规划——123. 买卖股票的最佳时机 III

目录 1、题目链接 2、题目分析 1.状态表示 2.状态转移方程 3.初始化 4.填表 5.返回值 3、代码解析 1、题目链接 123. 买卖股票的最佳时机 III 2、题目分析 1.状态表示 由题目可知&#xff0c;我们分为两种状态&#xff0c;买入和卖出&#xff0c;又因为只能完成两次交易…

MAC 查看公钥私钥

电脑配置过公钥私钥&#xff0c;现在需要查看&#xff1a; 1、 查看本地是否存在SSH密钥 命令&#xff1a;ls -al ~/.ssh 如果在输出的文件列表中发现id_rsa和id_rsa.pub的存在&#xff0c;证明本地已经存在SSH密钥&#xff0c;请执行第3步 2、 生成SSH密钥 命令&#xff1…

我的3次软考高项通关之旅

1、缘起 初次听说软考是在2022年下半年了&#xff0c;软考的高级分为很多种&#xff0c;我起先想报考高级架构师&#xff0c;但是架构师一年才考一次&#xff0c;如果一次考不过得再准备一年&#xff0c;时间对我来说太长了&#xff0c;于是我决定报考一年考两次的高项。对于国…

【Unity】RPG2D龙城纷争(六)关卡编辑器之角色编辑

更新日期&#xff1a;2024年6月26日。 项目源码&#xff1a;第五章发布&#xff08;正式开始游戏逻辑的章节&#xff09; 索引 简介一、角色编辑模式1.将字段限制为只读2.创建角色&#xff08;刷角色&#xff09;3.预览所有角色4.编辑选中角色属性5.移动角色位置6.移除角色 简介…

Linux OpenGrok搭建

文章目录 一、目的二、环境三、相关概念3.1 OpenGrok3.2 CTags3.3 Tomcat 四、OpenGrok搭建4.1 安装jdk4.2 安装ctags依赖4.3 安装universal-ctags4.3.1 下载universal-ctags4.3.2 编译&&安装universal-ctags 4.4 安装Tomcat4.4.1 下载&&解压Tomcat4.4.2 启动T…

HQChart使用教程30-K线图如何对接第3方数据41-分钟K线叠加股票增量更新

HQChart使用教程30-K线图如何对接第3方数据40-日K叠加股票增量更新 叠加股票叠加分钟K线更新Request 字段说明Data.symbol 协议截图返回json数据结构overlaydata HQChart代码地址交流 叠加股票 示例地址:https://jones2000.github.io/HQChart/webhqchart.demo/samples/kline_i…

泰迪智能科技大数据挖掘企业服务平台典型合作案例介绍

泰迪大数据挖掘企业服务平台 是一款通用的、企业级、智能化的数据分析模型构建与数据应用场景设计工具&#xff0c;能够一体化地完成数据集成、模型构建、模型发布&#xff0c;为数据分析、探索、服务流程提供支撑&#xff0c;提供完整的数据探索、多数据源接入、特征处理、模型…

软硬链接 以及 动静态链接

目录 1 软硬链接 2 动静态库 1 软硬链接 不知道大家也没有仔细看过我们的 windows 中的快捷方式的内容&#xff0c;我们右键点开一个快捷方式然后查看其属性&#xff0c;我们发现有一个 目标 的内容 这个目标是一串路径&#xff0c;这也就是我们的程序的安装路径中的一个.exe…

浅浅谈谈如何利用Javase+多线程+计算机网络的知识做一个爬CSDN阅读量总访问量的程序

目录 我们发现csdn的文章 首先为了印证我们的想法 我们用postman往csdn我们任意一篇文章发起post请求 发送请求 ​编辑获得响应结果 我们发现我们的阅读量上涨 PostRequestSender类 但是我们经过测试发现 定义一个字符串数组 把URL放进去 然后延迟启动 在线程池里面…

redis哨兵模式(Redis Sentinel)

哨兵模式的背景 当主服务器宕机后&#xff0c;需要手动把一台从服务器切换为主服务器&#xff0c;这就需要人工干预&#xff0c;费事费力&#xff0c;还会造成一段时间内服务不可用。这不是一种推荐的方式。 为了解决单点故障和提高系统的可用性&#xff0c;需要一种自动化的监…

司美格鲁肽在中国获批!深度解析报告附上

在中国&#xff0c;肥胖问题日益严重&#xff0c;但有效的治疗方法却相对匮乏。然而&#xff0c;这一现状随着国家药品监督管理局&#xff08;NMPA&#xff09;对诺和诺德公司研发的司美格鲁肽注射液&#xff08;商品名&#xff1a;诺和盈&#xff09;的批准而得到改变。6月25日…

JavaEE之HTTP协议(1)_HTTP基础知识,HTTP 请求、响应格式,方法,状态码

一、HTTP协议 1.1 基本概念: HTTP全称超文本传输协议&#xff0c;是一种无状态的、应用层的协议&#xff0c;它基于请求/响应模型。客户端&#xff08;通常是Web浏览器&#xff09;通过发送HTTP请求到服务器来获取或发送信息&#xff0c;服务器则返回HTTP响应作为回应。HTTP协…