Java函数式编程+Lambda表达式

文章目录

  • 函数式编程介绍
  • 纯函数
  • Lambda表达式基础
    • Lambda的引入
      • 传统方法
        • 1. 顶层类
        • 2. 内部类
        • 3. 匿名类
      • Lambda
  • 函数式接口(Functional Interface)
        • 1. **函数式接口的定义**
          • 示例:
        • 2. **函数式接口与Lambda表达式的关系**
          • 关联逻辑:
          • 示例:
        • 3. **JDK内置的函数式接口**
          • 常见接口:
        • 4. **Lambda表达式使用函数式接口的典型例子**
  • **方法引用(Method Reference)详解**
    • **1. 方法引用的基本概念**
        • **方法引用的语法结构**:
    • **2. 方法引用的四种形式**
      • **2.1 引用静态方法**
      • **2.2 引用特定对象的实例方法**
      • **2.3 引用构造方法**
    • **3. 方法引用与函数式接口的关系**
    • **4. 方法引用的实际应用**
  • 常用的函数式接口
    • **1. Consumer接口(级联多个Consumer)**
        • **Consumer的基本用法**
        • **级联Consumer - andThen方法**
        • **更复杂的级联示例**
    • **2. Predicate接口与对象查找**
        • **Predicate的基本概念**
        • **对象查找中的应用**
    • **3. Function接口及相关接口**
        • **Function的基本概念**
        • **示例代码**
        • **相关接口**

函数式编程介绍

Java8新引入函数式编程方式,大大的提高了编码效率。
从面向对象编程视角来看,程序中使用的变量,其实只是一个值的容器,这个容器中,可以放置不同的值。
从函数式编程视角,变量其实只是值的一个“别名”,值本身是不能改的
采用函数式编程思想设计类,强调“类”所封装的数据,应该只被初始化一次,之后就不再更改。
JDK中的String类型,就是用“函数式编程”风格设计出来的一个例子。

Java 8引入了Lambda表达式特性,提供了Stream API,其内置的函数支持动态组合和级联调用,能够方便地实现“声明式”的编程方式。

函数式与面向对象编程的基本构造元素:
面向对象编程,编程的基本单元是“类”,函数必须放在类中,从属于“类”。
函数式编程,以“函数”作为编程的基本构造块,函数之间可以相互协作和动态组合。

函数式编程能很容易地实现“行为的参数化”
函数封装了“行为”,在函数式编程中,是“把函数作为值”来看待的。
既然“函数是值”,那么它就可以作为另一个函数的参数或返回值,这个就是“行为的参数化”。
Java使用Lambda表达式来代表那些需要反复传递的行为,将其作为函数参数或返回值,从而实现了“行为参数化”。
这样讲有点抽象ヽ(´¬`)ノ,下面进行详细介绍。
在这里插入图片描述

纯函数

函数式编程中的“函数”,强调要消除“副作用”。
所谓“副作用”,就是指:
(1)函数的执行,受到其“运行上下文”的影响,在不同的运行环境中执行,会得到不同的结果。
(2)函数执行之后,会修改外界的数据,从而对外界的状态有所影响。
没有“副作用”的函数,可以放心地让多个线程调用。
抛出异常的函数,不满足“函数式编程”的要求

“纯函数”——没有副作用的函数:
一个方法是不是“Pure Function(纯函数)”,关键就是它的运行,是不是有“副作用(Side Effect)”。纯函数是没有副作用的,只要输入参数值一定,它的结果总是一致的,从而可以安全地被跨线程调用而无需考虑线程同步问题。


public class SideEffectIllustration {// 没有副作用的方法public int f1(int x) {return x * 2;}private int state = 0;// 有副作用的方法public int f2(int x) {state++;return x * 2 + state;}public static void main(String[] args) {SideEffectIllustration obj = new SideEffectIllustration();//创建10个线程,每个线程都调用f1或f2方法,观察多线程环境下//Pure Function的输出与有副作用的方法的输出有何区别Thread[] theads = new Thread[10];for (int i = 0; i < theads.length; i++) {final int index = i;theads[i] = new Thread(() -> {// Note:切换以下两句的注释,观察输出的结果System.out.println(String.format("第%d次,结果为:%d", index + 1, obj.f1(5)));//System.out.println(String.format("第%d次,结果为:%d", index + 1, obj.f2(5)));});theads[i].start();}}}

在实际开发中,推荐尽量编写“纯函数”。

Lambda表达式基础

Lambda的引入

我们把只定义有一个抽象方法的接口,称为“单一抽象方法(SAM:Single Abstract Method)”的接口,在开发中可以有三种方式实现它:

传统方法

1. 顶层类
interface MyInterface {void func();
}class MyClass implements MyInterface {@Overridepublic void func() {System.out.println("MyClass's func()");}
}

上述代码定义了一个MyInterface接口(它只定义了一个抽象方法,所以是SAM接口),接着,写了一个MyClass类实现这个接口,在这里,MyClass是一个顶层类。

然后,写了一个静态方法调用接口定义的方法:

    public static void doWithMyInterface(MyInterface obj) {obj.func();}

使用传统编程方式,上面的代码是这样被调用的:

        //传统方法,定义一个类实现接口,创建这个类的对象,//再把它传给doWithMyInterface()方法MyClass obj = new MyClass();doWithMyInterface(obj);
2. 内部类

除了使用顶层类,也可以使用内部类实现接口:
内部类的适用场景,主要是“仅在本类内部使用”,不需要被外界调用,并且代码比较简短。

        class MyInnerClass implements MyInterface{@Overridepublic void func() {System.out.println("本地内部类,实现接口");}}//实例化本地内部类对象,传给示例方法doWithMyInterface(new MyInnerClass());
3. 匿名类

如果代码仅在特定方法内部调用,并且代码量也不大,可以直接使用匿名内部类实现接口:

doWithMyInterface(new MyInterface() {@Overridepublic void func() {System.out.println("使用匿名内部类,实现接口");}});

Lambda

前面的代码是传统的经典的Java面向对象编程代码, 在开发中使用接口,所有代码可以很明确地分为“第一步、第二步、第三步……”,很易于理解,也很规范,但每次都需要手工做这么多的事,似乎有点过于麻烦了。
为了便捷性考虑,Java设计者借鉴其他编程语言,把Lambda特性引入到了Java中。
就可以把上述的代码写成这样的形式。

        //定义一个Lambda表达式,将其引用保存到变量中,//再把它传给doWithMyInterface()方法//从而可以节省下新定义一个类的工作任务MyInterface lambdaObj = () -> {System.out.println("Explicit Define Lambda object's func()");};doWithMyInterface(lambdaObj);

可以更进一步地简化为:

        //直接把一个Lambda表达式作为doWithMyInterface()方法的参数//不仅不需要定义一个单独的类,甚至不再需要定义一个变量doWithMyInterface(() -> {System.out.println("inline lambda object's func()");});

** 直接执行Lambda表达式:**
要“执行”一个Lambda表达式所封装的代码,需要使用关联接口所定义的方法:

        MyInterface lambdaObj2 = () -> {System.out.println("另一个Lambda表达式");};//Lambda表达式,也可以直接执行lambdaObj2.func();

在函数式编程代码中,函数与其它数据类型一样,也可以进行“赋值”和“传送”,具体来说,就是可以定义“函数类型”的变量,函数可以成为另一个函数的“参数”,函数也可以返回“另一个函数”。
可以把Lambda表达式理解为一种简洁的可传递匿名函数:它没有名称,但有参数列表,函数主体,返回类型,可能还有一个可以抛出的异常列表。

Lambda表达式格式:(如果方法体只有单行的话,可以把大括号去掉)

(参数列表) -> { 方法体 }

这是一些常见的Lambda使用例子:
在这里插入图片描述
再举一个完整的例子:


import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;public class UseComparator {public static void main(String args[]) {List<String> strings = new ArrayList<String>();strings.add("CCC");strings.add("ddd");strings.add("EEE");strings.add("AAA");strings.add("bbb");//使用Lambda表达式重写上述代码段Comparator<String> comparator = (str1, str2) -> {return str1.compareToIgnoreCase(str2);};strings.sort(comparator);System.out.println("Sort with comparator");//输出排序结果for (String str : strings) {System.out.println(str);}}
}

我们可以用Lambda表达式来写comparator方法,并在sort中利用这个方法进行排序。

现在知道了如何编写Lambda表达式,但在哪里使用呢?可以通过函数式接口来使用Lambda表达式。
Java通过“函数式接口”+ Lambda表达式,实现函数式编程。

函数式接口(Functional Interface)

能接收一个Lambda表达式的变量,必须是接口类型,并且这种接口,还必须是一种“函数式接口(functional interface)”。

所谓“函数式接口”,就是“只定义有一个抽象方法的接口”,在Java 8之前,这种接口被称为“SAM:Single Abstract Method”接口。

Java 8中,使用“@FunctionalInterface”标识一个“函数式接口”。

函数式接口 是 Java 8 引入的一个概念,指 只有一个抽象方法 的接口。
它是 Lambda 表达式的基础,Lambda 表达式可以直接替代函数式接口的实现。


1. 函数式接口的定义

函数式接口在语法上与普通接口无异,但必须确保只有一个抽象方法。

示例:
@FunctionalInterface
public interface MyFunction {int apply(int x, int y); // 唯一的抽象方法
}

注意:

  • Java 8 提供了 @FunctionalInterface 注解,用于显式声明一个接口为函数式接口。
  • 如果有多个抽象方法,编译器会报错。

即使不加 @FunctionalInterface,接口只有一个抽象方法时,依然可以作为函数式接口使用。


2. 函数式接口与Lambda表达式的关系

Lambda表达式的本质 是一种简化语法,用来表示函数式接口的实例。
当一个 Lambda 表达式被传递时,JVM 自动将其映射为对应函数式接口的实现。

关联逻辑:
  1. 函数式接口提供了唯一的抽象方法
  2. Lambda 表达式的代码实现对应函数式接口的唯一抽象方法。
示例:
@FunctionalInterface
interface MyFunction {int apply(int x, int y);
}// 使用Lambda表达式实现MyFunction接口
MyFunction add = (x, y) -> x + y;System.out.println(add.apply(3, 5)); // 输出: 8

解释:

  • MyFunction 是一个函数式接口。
  • Lambda表达式 (x, y) -> x + y 实现了 apply 方法。

3. JDK内置的函数式接口

Java 提供了许多内置的函数式接口,位于 java.util.function 包中。这些接口可以直接配合 Lambda 表达式使用。

常见接口:
  1. Predicate<T>:接收一个参数,返回布尔值。

    Predicate<Integer> isEven = n -> n % 2 == 0;
    System.out.println(isEven.test(4)); // 输出: true
    
  2. Consumer<T>:接收一个参数,无返回值。

    Consumer<String> print = s -> System.out.println(s);
    print.accept("Hello, Lambda!"); // 输出: Hello, Lambda!
    
  3. Function<T, R>:接收一个参数,返回一个结果。

    Function<Integer, String> intToString = n -> "Number: " + n;
    System.out.println(intToString.apply(10)); // 输出: Number: 10
    
  4. Supplier<T>:无参数,返回一个结果。

    Supplier<Double> random = () -> Math.random();
    System.out.println(random.get()); // 输出: 随机数
    
  5. BiFunction<T, U, R>:接收两个参数,返回一个结果。

    BiFunction<Integer, Integer, Integer> multiply = (a, b) -> a * b;
    System.out.println(multiply.apply(3, 4)); // 输出: 12
    

4. Lambda表达式使用函数式接口的典型例子
  1. 线程启动:使用 Runnable 接口

    // 传统写法
    new Thread(new Runnable() {@Overridepublic void run() {System.out.println("Thread running...");}
    }).start();// 使用Lambda
    new Thread(() -> System.out.println("Thread running...")).start();
    
  2. 集合操作:Comparator接口

    List<String> names = Arrays.asList("Alice", "Bob", "Charlie");// 使用Lambda表达式简化排序
    names.sort((a, b) -> a.compareTo(b));
    System.out.println(names);
    
  3. 事件处理:ActionListener接口

    JButton button = new JButton("Click Me");
    button.addActionListener(e -> System.out.println("Button clicked!"));
    

在这里插入图片描述

方法引用(Method Reference)详解

方法引用 是 Java 8 引入的一种简化 Lambda 表达式的语法,允许开发者通过直接引用已有方法来实现函数式接口的抽象方法,从而使代码更简洁、更可读。
Lambda表达式可以进一步简化为方法引用,直接使用现有方法实现接口的抽象方法。

每个方法引用都存在一个等效的 lambda 表达式

1. 方法引用的基本概念

  • 方法引用是 Lambda 表达式的简化形式。
  • 它使用双冒号 :: 操作符来引用方法。
  • 适用于 Lambda 表达式仅调用一个已有方法的场景。
方法引用的语法结构
ClassName::methodName

例如:

// Lambda 表达式
Function<String, Integer> lambda = s -> Integer.parseInt(s);// 方法引用
Function<String, Integer> methodRef = Integer::parseInt;

在这两个例子中,Integer::parseInts -> Integer.parseInt(s) 的简化形式。


2. 方法引用的四种形式

2.1 引用静态方法

适用于 Lambda 表达式调用某个类的静态方法。

语法:

ClassName::staticMethod

示例:

// Lambda 表达式
Function<String, Integer> lambda = s -> Integer.parseInt(s);// 方法引用
Function<String, Integer> methodRef = Integer::parseInt;System.out.println(methodRef.apply("123")); // 输出: 123

分析:

  • Lambda 表达式 s -> Integer.parseInt(s) 调用的是 Integer 类的静态方法 parseInt
  • 通过 Integer::parseInt 简化了代码。

2.2 引用特定对象的实例方法

适用于 Lambda 表达式调用特定对象的实例方法。

语法:

instance::instanceMethod

示例1:

// 特定对象
String str = "Hello";// Lambda 表达式
Supplier<Integer> lambda = () -> str.length();// 方法引用
Supplier<Integer> methodRef = str::length;System.out.println(methodRef.get()); // 输出: 5

分析:

  • Lambda 表达式 () -> str.length() 调用的是 str 对象的 length 方法。
  • 通过 str::length 简化代码。

示例2:

// Lambda 表达式
BiFunction<String, String, Boolean> lambda = (s1, s2) -> s1.equals(s2);// 方法引用
BiFunction<String, String, Boolean> methodRef = String::equals;System.out.println(methodRef.apply("abc", "abc")); // 输出: true
System.out.println(methodRef.apply("abc", "def")); // 输出: false

分析:

  • Lambda 表达式 (s1, s2) -> s1.equals(s2) 调用的是 String 类实例的 equals 方法。
  • 通过 String::equals 进一步简化。

2.3 引用构造方法

适用于 Lambda 表达式用于创建对象的场景。

语法:

ClassName::new

示例:

// Lambda 表达式
Supplier<List<String>> lambda = () -> new ArrayList<>();// 方法引用
Supplier<List<String>> methodRef = ArrayList::new;List<String> list = methodRef.get();
System.out.println(list); // 输出: []

带参数的构造方法引用:

// Lambda 表达式
Function<String, Integer> lambda = s -> new Integer(s);// 方法引用
Function<String, Integer> methodRef = Integer::new;System.out.println(methodRef.apply("123")); // 输出: 123

3. 方法引用与函数式接口的关系

方法引用本质上是对函数式接口的实现。

  • 函数式接口 要求实现唯一的抽象方法。
  • 方法引用 的方法与该抽象方法的签名必须一致。

示例:

@FunctionalInterface
interface MyFunction {void print(String s);
}// 使用 Lambda 表达式
MyFunction lambda = s -> System.out.println(s);// 使用方法引用
MyFunction methodRef = System.out::println;lambda.print("Hello, Lambda!");   // 输出: Hello, Lambda!
methodRef.print("Hello, Method Reference!"); // 输出: Hello, Method Reference!

4. 方法引用的实际应用

  1. 集合排序
List<String> names = Arrays.asList("Bob", "Alice", "Charlie");// 使用 Lambda 表达式
names.sort((a, b) -> a.compareTo(b));// 使用方法引用
names.sort(String::compareTo);System.out.println(names); // 输出: [Alice, Bob, Charlie]
  1. 流处理(Stream API)
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");// 使用 Lambda 表达式
names.stream().map(name -> name.toUpperCase()).forEach(name -> System.out.println(name));// 使用方法引用
names.stream().map(String::toUpperCase).forEach(System.out::println);

常用的函数式接口

1. Consumer接口(级联多个Consumer)

Consumer的基本用法

Consumer<T> 接口用于接收一个输入参数并对其执行某些操作,但不会返回结果。常见用法是打印日志、更新状态、操作集合元素等。

  • 核心方法:
    void accept(T t);
    
    • 接收一个参数 t,对其执行操作。
    • 没有返回值。
级联Consumer - andThen方法

Consumer 提供了默认方法 andThen,可以将多个 Consumer 串联起来,按照顺序依次执行每个 Consumer 的逻辑。

  • 方法定义:

    default Consumer<T> andThen(Consumer<? super T> after)
    
    • 参数 after: 另一个 Consumer,会在当前 Consumer 执行完之后被调用。
    • 返回一个新的 Consumer,依次执行两个 Consumer 的操作。
  • 示例代码:

    public static void main(String[] args) {Consumer<String> consumer1 = str -> System.out.println("Consumer 1: " + str);Consumer<String> consumer2 = str -> System.out.println("Consumer 2: " + str.toUpperCase());// 将两个Consumer级联Consumer<String> combinedConsumer = consumer1.andThen(consumer2);combinedConsumer.accept("hello");
    }
    
    • 输出:
      Consumer 1: hello
      Consumer 2: HELLO
      

更复杂的级联示例

可以串联多个 Consumer 来实现更复杂的操作。

public static void main(String[] args) {Consumer<String> consumer1 = str -> System.out.println("Step 1: " + str.trim());Consumer<String> consumer2 = str -> System.out.println("Step 2: " + str.toLowerCase());Consumer<String> consumer3 = str -> System.out.println("Step 3: " + str.toUpperCase());// 级联三个ConsumerConsumer<String> combinedConsumer = consumer1.andThen(consumer2).andThen(consumer3);combinedConsumer.accept("  HeLLo WoRLd  ");
}
  • 输出:
    Step 1: HeLLo WoRLd
    Step 2: hello world
    Step 3: HELLO WORLD
    

2. Predicate接口与对象查找

Predicate的基本概念

Predicate<T> 接口主要用于定义一个“判断规则”,用于表示一个“布尔值”函数。它接收一个输入参数,并返回一个布尔值,用于条件判断。
在这里插入图片描述

  • 核心方法:

    boolean test(T t);
    
    • 参数 t: 输入值。
    • 返回值:布尔值,用于判断输入是否满足条件。
  • 默认方法:

    • and: 将多个 Predicate 串联,所有条件均为 true 时返回 true
    • or: 至少一个条件为 true 时返回 true
    • negate: 对当前 Predicate 结果取反。
    • isEqual: 检查对象是否相等。

对象查找中的应用

Predicate 通常用于过滤集合、查找符合条件的对象。

  • 示例代码(查找满足条件的对象):

    public static void main(String[] args) {List<String> names = List.of("Alice", "Bob", "Charlie", "David");// 定义Predicate,查找长度大于3的名字Predicate<String> lengthPredicate = name -> name.length() > 3;// 查找符合条件的名字names.stream().filter(lengthPredicate).forEach(System.out::println);
    }
    
    • 输出:
      Alice
      Charlie
      David
      
  • 级联使用多个Predicate:

  • 在这里插入图片描述

    Predicate<String> startsWithA = name -> name.startsWith("A");
    Predicate<String> lengthPredicate = name -> name.length() > 3;// 组合条件:以A开头且长度大于3
    Predicate<String> combinedPredicate = startsWithA.and(lengthPredicate);names.stream().filter(combinedPredicate).forEach(System.out::println);
    
    • 输出:
      Alice
      

3. Function接口及相关接口

Function的基本概念

Function<T, R> 是 Java 8 中的函数式接口,此接口定义了一个apply方法,它接收一个T类型的对象,返回一个R类型的对象:
在这里插入图片描述

  • 核心方法:

    R apply(T t);
    
    • 参数 t: 输入值。
    • 返回值:类型为 R 的结果。
  • 默认方法:

    • andThen: 先执行当前 Function,再将结果传给另一个 Function
    • compose: 先执行参数指定的 Function,再将结果传递给当前 Function

示例代码
  • 基本用法:

    public static void main(String[] args) {Function<String, Integer> stringLength = str -> str.length();System.out.println(stringLength.apply("Hello")); // 输出 5
    }
    
  • 使用 andThencompose:

    public static void main(String[] args) {Function<String, Integer> stringLength = str -> str.length();Function<Integer, Integer> square = num -> num * num;// andThen: 先计算长度,再平方System.out.println(stringLength.andThen(square).apply("Hello")); // 输出 25// compose: 先平方长度,再计算平方System.out.println(square.compose(stringLength).apply("Hello")); // 输出 25
    }
    

相关接口
  1. BiFunction<T, U, R>
    作为Function接口的特例,有一个BiFunction<T, U, R>接口,它所定义的apply方法接收两个参数:T和U类型的,然后返回一个R类型的对象。
    在这里插入图片描述

    • 表示一个接收两个参数的函数,返回一个结果。

    • 核心方法:

      R apply(T t, U u);
      
    • 示例:

      BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
      System.out.println(add.apply(5, 10)); // 输出 15
      
  2. UnaryOperator

    • Function<T, T> 的子接口,表示输入和输出类型相同的函数。其实就是Function<T,T>的简写。
      在这里插入图片描述

    • 示例:

      UnaryOperator<Integer> square = x -> x * x;
      System.out.println(square.apply(5)); // 输出 25
      
  3. BinaryOperator

    • BiFunction<T, T, T> 的子接口,等价于BiFunction<T,T,T>,表示两个相同类型参数的函数,并返回相同类型的结果。
      在这里插入图片描述

    • 示例:

      BinaryOperator<Integer> multiply = (a, b) -> a * b;
      System.out.println(multiply.apply(2, 3)); // 输出 6
      
  4. IntToDoubleFunction

    • 表示接收一个 int 类型参数并返回一个 double 类型结果的函数。
    • 示例:
      IntToDoubleFunction half = x -> x / 2.0;
      System.out.println(half.applyAsDouble(10)); // 输出 5.0
      

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

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

相关文章

Linux操作系统2-进程控制3(进程替换,exec相关函数和系统调用)

上篇文章&#xff1a;Linux操作系统2-进程控制2(进程等待&#xff0c;waitpid系统调用&#xff0c;阻塞与非阻塞等待)-CSDN博客 本篇代码Gitee仓库&#xff1a;Linux操作系统-进程的程序替换学习 d0f7bb4 橘子真甜/linux学习 - Gitee.com 本篇重点&#xff1a;进程替换 目录 …

文件上传漏洞:你的网站安全吗?

文章目录 文件上传漏洞攻击方式&#xff1a;0x01绕过前端限制0x02黑名单绕过1.特殊解析后缀绕过2..htaccess解析绕过3.大小写绕过4.点绕过5.空格绕过6.::$DATA绕过7.配合中间件解析漏洞8.双后缀名绕过9.短标签绕过 0x03白名单绕过1.MIME绕过(Content-Type绕过)2.%00截断3.0x00截…

设计模式-适配器模式-注册器模式

设计模式-适配器模式-注册器模式 适配器模式 如果开发一个搜索中台&#xff0c;需要适配或接入不同的数据源&#xff0c;可能提供的方法参数和平台调用的方法参数不一致&#xff0c;可以使用适配器模式 适配器模式通过封装对象将复杂的转换过程隐藏于幕后。 被封装的对象甚至…

springboot341+vue校园求职招聘系统设计和实现pf(论文+源码)_kaic

毕 业 设 计&#xff08;论 文&#xff09; 校园求职招聘系统设计与实现 摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;…

基于java web的网上书店系统设计

摘 要 随着互联网的越发普及&#xff0c;网上购物成为了当下流行的热门行为。网络上开店创业有许多的优势&#xff1a;投入少&#xff0c;启动 资金低&#xff0c;交易便捷。网上书店与传统的线下书店比起来优势巨大&#xff0c;网上书店的经营方式和销售渠道是不同与线下书 店…

Java设计模式——职责链模式:解锁高效灵活的请求处理之道

嘿&#xff0c;各位 Java 编程大神和爱好者们&#xff01;今天咱们要一同深入探索一种超厉害的设计模式——职责链模式。它就像一条神奇的“处理链”&#xff0c;能让请求在多个对象之间有条不紊地传递&#xff0c;直到找到最合适的“处理者”。准备好跟我一起揭开它神秘的面纱…

Android 设备使用 Wireshark 工具进行网络抓包

背景 电脑和手机连接同一网络&#xff0c;想使用wireshark抓包工具抓取Android手机网络日志&#xff0c;有以下两种连接方法&#xff1a; Wi-Fi 网络抓包。USB 网络共享抓包。需要USB 数据线将手机连接到电脑&#xff0c;并在开发者模式中启用 USB 网络共享。 查看设备连接信…

redis大key和热key

redis中大key、热key 什么是大key大key可能产生的原因大key可能会造成什么影响如何检测大key如何优化删除大key时可能的问题删除大key的策略 热key热key可能导致的问题解决热key的方法 什么是大key 大key通常是指占用内存空间过大或包含大量元素的键值对。 数据量大&#xff…

SpringBoot源码-spring boot启动入口ruan方法主线分析(二)

12.刷新前操作 // 刷新前操作prepareContext(context, environment, listeners, applicationArguments, printedBanner);进入prepareContext private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,SpringApplicationRun…

使用 VLC 在本地搭建流媒体服务器 (详细版)

提示&#xff1a;详细流程 避坑指南 Hi~&#xff01;欢迎来到碧波空间&#xff0c;平时喜欢用博客记录学习的点滴&#xff0c;欢迎大家前来指正&#xff0c;欢迎欢迎~~ ✨✨ 主页&#xff1a;碧波 &#x1f4da; &#x1f4da; 专栏&#xff1a;音视频 目录 借助VLC media pl…

【单片机毕业设计12-基于stm32c8t6的智能称重系统设计】

【单片机毕业设计12-基于stm32c8t6的智能称重系统设计】 前言一、功能介绍二、硬件部分三、软件部分总结 前言 &#x1f525;这里是小殷学长&#xff0c;单片机毕业设计篇12-基于stm32c8t6的智能称重系统设计 &#x1f9ff;创作不易&#xff0c;拒绝白嫖可私 一、功能介绍 ----…

51单片机快速入门之中断的应用 2024/11/23 串口中断

51单片机快速入门之中断的应用 基本函数: void T0(void) interrupt 1 using 1 { 这里放入中断后需要做的操作 } void T0(void)&#xff1a; 这是一个函数声明&#xff0c;表明函数 T0 不接受任何参数&#xff0c;并且不返回任何值。 interrupt 1&#xff1a; 这是关键字和参…

输入json 达到预览效果

下载 npm i vue-json-pretty2.4.0 <template><div class"newBranchesDialog"><t-base-dialogv-if"addDialogShow"title"Json数据配置"closeDialog"closeDialog":dialogVisible"addDialogShow":center"…

ML 系列:第 32节 — 机器学习中的统计简介

文章目录 一、说明二、统计概述三、描述性统计与推断性统计3.1 描述统计学3.2 推论统计 四、描述性统计中的均值、中位数和众数 一、说明 机器学习中的统计 随着我们深入研究机器学习领域&#xff0c;了解统计学在该领域的作用至关重要。统计学是机器学习的支柱&#xff0c;它…

大数据新视界 -- Hive 数据分区:精细化管理的艺术与实践(上)(7/ 30)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

VTK的基本概念(一)

文章目录 三维场景的基本要素1.灯光2.相机3.颜色4.纹理映射 三维场景的基本要素 1.灯光 在三维渲染场景中&#xff0c;可以有多个灯光的存在&#xff0c;灯光和相机是三维渲染场景的必备要素&#xff0c;如果没有指定的话&#xff0c;vtkRenderer会自动创建默认的灯光和相机。…

简单好用的折线图绘制!

折线图的概念及作用&#xff1a; 折线图&#xff08;Line Chart&#xff09;是一种常见的图表类型&#xff0c;用于展示数据的变化趋势或时间序列数据。它通过一系列的数据点&#xff08;通常表示为坐标系中的点&#xff09;与这些点之间的线段相连&#xff0c;直观地展示变量…

简单线性DP

数字三角形--简单线性DP 题目链接&#xff1a;数字三角形 解题代码&#xff1a; import java.io.BufferedReader; import java.io.InputStreamReader;public class Main {static int N510;static int INF (int) -1e9;static String[] q;static int[][]fnew int[N][N];static …

【数据结构】双向链表、单向循环链表、双向循环链表、栈、链栈

目录 一、双向链表 定义类和封装函数以及测试样例如下&#xff1a; 注意事项&#xff1a; 二、循环链表 单循环列表的类和函数封装如下&#xff1a; 注意事项&#xff1a; 三、双向循环链表 结点类和双循环链表的定义部分 函数封装之判空和尾插 双循环链表遍历 双循…

win10中使用ffmpeg的filter滤镜

1 给视频加文字水印 1.1 添加播放时间 ffmpeg -i input.mp4 -vf "drawtextfontfileC\\:/Windows/fonts/consola.ttf:fontsize30:fontcolorwhite:timecode00\:00\:00\:00:rate25:textTCR\::boxcolor0x000000AA:box1:x20:y20" -y output.mp4 在视频的x20:y20位置添加t…