当前位置: 首页 > news >正文

JDK8新特性详解

☆* o(≧▽≦)o *☆嗨~我是小奥🍹
📄📄📄个人博客:小奥的博客
📄📄📄CSDN:个人CSDN
📙📙📙Github:传送门
📅📅📅面经分享(牛客主页):传送门
🍹文章作者技术和水平有限,如果文中出现错误,希望大家多多指正!
📜 如果觉得内容还不错,欢迎点赞收藏关注哟! ❤️

文章目录

  • JDK8新特性详解
    • 1、接口
    • 2、Lambda表达式
    • 3、函数式接口
    • 4、引用
      • (1) 方法引用
      • (2) 构造器引用
      • (3) 数组引用
    • 5、Stream API
      • (1) 什么是Stream
      • (2) 创建
      • (3) 筛选/ 切片
      • (4) 映射
      • (5) 排序
      • (6) 查找 / 匹配
      • (7) 归约 / 收集
      • (8) 并行流
    • 6、Optional
    • 7、新时间日期API
      • (1) 安全问题
      • (2) 本地时间 / 日期
      • (3) 时间戳
      • (4) 时间/日期差
      • (5) 时间校正器
      • (6) 时间格式化
      • (7) 时区
    • 8、Annotations注解
      • (1) 类型注解
      • (2) 重复注解

JDK8新特性详解

1、接口

Java8对接口做了进一步的增强。

  • 在接口中添加使用default关键字修饰的非抽象方法,即:默认方法。
  • 接口中可以声明静态方法,并且可以实现 。

默认方法和静态方法:

Java8 允许我们通过default关键字对接口中定义的抽象方法提供一个默认的实现。

    public interface MyInterface {// 一个普通的方法void method(int var);// 一个默认的方法default void defaultMethod(int var) {System.out.println("执行接口的 default 方法");}// 一个静态方法static void staticMethod() {System.out.println("执行接口的 static 方法");}}

在上面这个接口中,我们除了定义了一个抽象方法 calculate,还定义了一个带有默认实现的方法 sqrt。 我们在实现这个接口时,可以只需要实现 calculate 方法,默认方法 sqrt 可以直接调用即可,也就是说我们可以不必强制实现 sqrt 方法。

通过default关键字的特性,我们可以很方便的对之前的接口进行扩展,而此接口的实现类不必做出任何改动。

	public static void main(String[] args) {MyInterface anInterface = new MyInterface() {@Overridepublic void method(int a) {System.out.println("");}};anInterface.method(0);anInterface.defaultMethod(1);}

接口默认方法的类优先原则:

若一个接口中定义了一个默认方法,而另外一个父类或者接口中又定义了一个同名的方法时:

  • **选择父类中的方法。**如果一个父类提供了具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略。
  • **接口冲突。**如果一个父接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认方法),那么必须覆盖该方法来解决冲突。

2、Lambda表达式

Lambda是一个匿名函数(没有函数名的函数),直接对应于其中的Lambda抽象,Lambda 表达式可以表示闭包。

可以理解为一段可以传递的代码(将代码像数据一样传递),可以写出更简洁、更灵活的代码;作为一种更紧凑的代码风格,是Java语言表达能力得到提升。

Lambda表达式允许把函数作为一个方法的参数,基本表达如下:

 (parameters) -> expression 或 (parameters) -> {statements;}

(1)无参数,无返回值

例如,Runnable接口:

		Runnable r1 = new Runnable() {@Overridepublic void run() {System.out.println("java8之前");}};Runnable r2 = () -> {System.out.println("Lambda表达式写法");};

(2)有一个参数,无返回值

		Consumer<String> con1 = (a) -> System.out.println(a);con1.accept("lambda");// 小括号可以省略不写Consumer<String> con1 = a -> System.out.println(a);con1.accept("lambda");

(3)有两个及以上的参数,有返回值

		Comparator<Integer> com1 = (a, b) -> {System.out.println("lambda 比较");return Integer.compare(a, b);};// 方法体内部只有一条语句的时候,大括号可以省略Comparator<Integer> com2 = (a, b) -> Integer.compare(a, b);

3、函数式接口

Lambda表达式是用过函数式接口(只有一个方法的普通接口)来实现的,函数式接口可以被隐式转换为Lambda表达式,为了与普通的接口区分开,JDK1.8新增加了一种特殊的注解@FunctionalInterface 如下:

@FunctionalInterface
public interface Function<T, R> {/*** Applies this function to the given argument.** @param t the function argument* @return the function result*/R apply(T t);
}

(1)四大核心函数式接口

函数式接口参数类型返回类型用途
Consumer消费型接口Tvoid对类型为T的对象应用操作:viod accept(T t)
Supplier提供型接口T返回类型为T的对象:T get()
Function<T, R>函数型接口TR对类型为T的对象应用操作,并返回结果为R类型的对象:R apply(T t)
Predicate断言型接口Tboolean确定类型为T的对象是否满足某约束,并返回boolean值:boolean test(T t)

(2)Consumer消费型接口

		Consumer<Integer> consumer = x -> System.out.println("消费型接口" + x);consumer.accept(1);

(3)Supplier提供型接口

        Supplier<Integer> supplier = () -> (int)(Math.random() * 10);System.out.println(supplier.get());

(4)Function函数型接口

        String str = "123xyz";Function<String, String> function = s -> s.substring(1, 5);System.out.println(function.apply(str));

(5)Predicate断言型接口

        Integer age = 30;Predicate<Integer> predicate = i -> i >= 35;if (predicate.test(age)) {System.out.println("退休");} else {System.out.println("继续加油");}

4、引用

(1) 方法引用

若Lambda表达式中的内容已经有方法实现,则我们可以使用方法引用。

语法格式:

	对象::实例方法类::静态方法类::实例方法

注意:Lambda表达实体中调用的方法参数列表,返回类型必须和函数式接口中抽象方法保持一致。

① 对象::实例方法

		Consumer<String> con1 = s -> System.out.println(s);con1.accept("123");Consumer<String> con2 = System.out::println;con2.accept("456");

② 类::静态方法

		Comparator<Integer> com1 = (x, y) -> Integer.compare(x, y);com1.compare(1, 2);Comparator<Integer> com2 = Integer::compare;com2.compare(3, 4);

③ 类::实例方法

		BiPredicate<String, String> bp1 = (x, y) -> x.equals(y);bp1.test("a", "b");BiPredicate<String, String> bp2 = String::equals;bp2.test("a", "b");

(2) 构造器引用

格式:

	ClassName::New
		Supplier<List> sup1 = () -> new ArrayList<>();Supplier<List> sup2 = ArrayList::new;

(3) 数组引用

		Function<Integer, String[]> fun1 = count -> new String[count];Function<Integer, String[]> fun2 = String[]::new; 

5、Stream API

(1) 什么是Stream

流(Stream)是数据渠道,是用于操作数据源(集合、数组等 )所生成的元素序列。、

简单来说,就是我们对一个包含一个或者多个元素的集合做各种操作。

注意:

  • Stream不会存储元素 。
  • Stream不会改变源对象,会返回一个持有结果的新的Stream。
  • Stream的操作是延迟执行的。需要返回结果的时候才会执行。

Stream的操作过程如下:

(1)**创建Stream。**一个数据源(如:数组、集合),获取一个流。

(2)**中间操作。**一个中间操作链,对数据源的数据进行处理。

(3)终止操作(终端操作)。一个终止操作,执行中间操作链,并产生结果。

(2) 创建

创建流的几种方式如下:

    // 1、通过集合获取流        ArrayList<Object> list = new ArrayList<>();Stream<Object> s1 = list.stream();// 2、通过数组获取流String[] strings = new String[10];Stream<String> s2 = Arrays.stream(strings);// 3、通过Stream的静态方法获取Stream<Integer> s3 = Stream.of(1, 2, 3);// 4、通过迭代获取流Stream<Integer> s4 = Stream.iterate(0, i -> i++);// 5、生成流Stream.generate(() -> Math.random()).limit(5).forEach(System.out::println);

(3) 筛选/ 切片

中间操作:

  • filter:接收lambda,从流中排除元素。
  • limit:截断流,使其元素不超过给定数量。
  • skip(n):跳过元素,返回一个舍弃前n个元素的流;若流中元素不足n个,则返回一个空流。
  • distinct:筛选,通过流生成的hashCode()和equals()去除重复元素。
import java.util.Arrays;
import java.util.List;public class Main {public static void main(String[] args) {List<Person> list = Arrays.asList(new Person(1, "a", 20),new Person(2, "b", 21),new Person(3, "c", 22),new Person(4, "d", 23),new Person(5, "e", 24),new Person(6, "f", 25));list.stream().filter(x -> x.getAge() > 20)  // 条件过滤.limit(3) // 限制条数.distinct() // 去除重复.skip(1) // 跳过指定的条数.forEach(System.out::println); // 循环打印}
}class Person {private int id;private String name;private int age;public Person(int id, String name, int age) {this.id = id;this.name = name;this.age = age;}// getter and setter
}

多个中间操作可以连接起来形成一个流水线,除非流水线上的操作触发终止操作,否则中间操作 不会 执行任何的处理。而在终止操作时一次性全部处理,称为“惰性求值”。

(4) 映射

  • map:接收lambda,将元素转换为其他形式或者提取信息;接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
  • flatMap:接收一个函数作为参数,将流中每一个值都转换成另一个流,然后把所有流重新连接成一个流。
 		List<String> list = Arrays.asList("a", "b", "c");list.stream().map(str -> str.toUpperCase()) .forEach(System.out::println);
    public class Main {public static void main(String[] args) {List<String> list = Arrays.asList("a", "b", "c");list.stream().flatMap(Test::filterCharacter).forEach(System.out::println);}}class Test {public static Stream<Character> filterCharacter(String str) {List<Character> list = new ArrayList<>();for (char c : str.toCharArray()) {list.add(c);}return list.stream();}}

(5) 排序

  • sorted():自然排序
  • sorted(Comparator c):自定义排序

(6) 查找 / 匹配

终止操作:

  • allMatch:检查是否匹配所有元素
  • anyMatch:检查是否至少匹配一个元素
  • noneMatch:检查是否没有匹配所有元素
  • findFirst:返回第一个元素
  • findAny:返回当前流中的任意元素
  • count:返回流中元素的总个数
  • max:返回流中的最大值
  • min:返回流中的最小值
import java.util.Arrays;
import java.util.List;
import java.util.Optional;public class Main {public static void main(String[] args) {List<Status> list = Arrays.asList(Status.FREE, Status.BUSY, Status.VOCATION);// 匹配所有元素System.out.println(list.stream().allMatch(s -> s.equals(Status.BUSY)));// 至少匹配一个元素System.out.println(list.stream().anyMatch(s -> s.equals(Status.BUSY)));//  所有元素都不匹配System.out.println(list.stream().noneMatch(s -> s.equals(Status.BUSY)));//  返回第一个元素Optional<Status> first = list.stream().findFirst();// 避免空指针异常,如果Optional、为空,则找一个替换的对象Status status = first.orElse(Status.BUSY);System.out.println(status);// 返回任意一个元素Optional<Status> any = list.stream().findAny();System.out.println(any);// 返回流中元素的总个数System.out.println(list.stream().count());}
}enum Status {FREE, BUSY, VOCATION;
}

(7) 归约 / 收集

  • reduce(T identity, BinaryOperator) / reduce(BinaryOperator):归约,可以将流中的数据反复结合起来,得到一个值。
  • collect:收集,将流转换成其他形式;接收一个Controller接口实现,用于给流中元素做汇总的方法。
		List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);System.out.println(list.stream().reduce(0, (x, y) -> x + y));		
import java.util.*;
import java.util.stream.Collectors;public class Main {public static void main(String[] args) {List<Person> persons = Arrays.asList(new Person(1, "a", 20),new Person(2, "b", 21),new Person(3, "c", 22),new Person(4, "d", 23),new Person(5, "e", 24),new Person(6, "f", 25));// 放入listList<String> list = persons.stream().map(Person::getName).collect(Collectors.toList());list.forEach(System.out::println);// 放入setSet<String> set = persons.stream().map(Person::getName).collect(Collectors.toSet());set.forEach(System.out::println);// 放入LinkedHashLinkedHashSet<String> linkedHashSet = persons.stream().map(Person::getName).collect(Collectors.toCollection(LinkedHashSet::new));linkedHashSet.forEach(System.out::println);// 总数System.out.println(persons.stream().collect(Collectors.counting()));// 平均值System.out.println(persons.stream().collect(Collectors.averagingInt(Person::getAge)));// 总和System.out.println(persons.stream().collect(Collectors.summingInt(Person::getId)));// 最大值System.out.println(persons.stream().collect(Collectors.maxBy((a, b) -> Integer.compare(a.getAge(), b.getAge()))));// 最小值System.out.println(persons.stream().collect(Collectors.minBy((a, b) -> Integer.compare(a.getAge(), b.getAge()))));// 分组Map<Integer, List<Person>> map = persons.stream().collect(Collectors.groupingBy(Person::getId));System.out.println(map);// 多级分组Map<Integer, Map<String, List<Person>>> mapMap = persons.stream().collect(Collectors.groupingBy(Person::getId, Collectors.groupingBy(e -> {if (e.getAge() > 20) {return "符合条件";} else {return "不符合条件";}})));System.out.println(mapMap);// 分区Map<Boolean, List<Person>> listMap = persons.stream().collect(Collectors.partitioningBy(e -> e.getAge() > 21));System.out.println(listMap);// 总结IntSummaryStatistics collect = persons.stream().collect(Collectors.summarizingInt(Person::getAge));System.out.println(collect.getMax());System.out.println(collect.getMin());System.out.println(collect.getSum());System.out.println(collect.getAverage());System.out.println(collect.getCount());// 连接String connect = persons.stream().map(Person::getName).collect(Collectors.joining("-"));}
}class Person {private int id;private String name;private int age;public Person(int id, String name, int age) {this.id = id;this.name = name;this.age = age;}// getter and setter// toString
}

(8) 并行流

并行流:就是把一个内容分成几个数据块,并用不同的线程分别处理每个数据块的流。

Java8中将并行流进行了优化,我们可以很容易的对数据进行操作;Stream API可以声明性地通过parallel()与sequential()在并行流与串行流之间切换。

    // 串行流(单线程):切换为并行流parallel()// 并行流(多线程):切换为串行流sequential()LongStream.rangeClosed(0, 10000000L).parallel() // 底层使用的是Fork/Join框架.reduce(0, Long::sum);

6、Optional

Optional类是一个容器类,代表一个值存在或者不存在,原来使用null表示一个值不存在,现在可以用Optional可以更好的表达这个概念,并且可以避免空指针异常。

常用方法:

  • Optional.of(T t):创建一个Optional实例。
  • Optional'empty(T t):创建一个空的Optional实例。
  • OpTional.OfNullable(T t):若t不为null,则创建Optional实例,否则空实例。
  • isPresent():判断是否包含某值。
  • orElse(T t):如果调用对象包含值,返回该值,否则返回t。
  • orElseGet(Supplier s):如果调用对象包含值,返回该值,否则返回s获取的值。
  • map(Function f):如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty()。
  • flatmap(Function mapper):与map相似,要求返回值必须是Optional。

7、新时间日期API

(1) 安全问题

Java之前的Date时间类,存在很多的缺点 。

(1)最开始的时候,Date既要承载日期信息,又要做日期之间的转换,还要做不同日期格式的显示,职责较繁杂,从JDK1.1开始,这三项职责分开了:

  • 使用Calendar类实现日期和时间字段之间转换
  • 使用DateFormat类来格式化和分析日期字符串
  • Date只用来承载日期和时间信息

(2)对year和month的表达。

    Date date = new Date(2012,1,1);System.out.println(date);//输出Thu Feb 01 00:00:00 CST 3912

观察输出结果,year是2012 + 1900,而month是 1+1,如果要设置日期,我们应该使用java.util.Calendar,如下:

		Calendar calendar = Calendar.getInstance();calendar.set(2013, 8, 2);// 输出 Mon Sep 02 17:11:58 CST 2013System.out.println(calendar.getTime());calendar.set(2013, Calendar.AUGUST, 2);// 输出 Fri Aug 02 17:13:53 CST 2013System.out.println(calendar.getTime());

不过这样,month的表示还是从0开始的,除非我们直接使用枚举类型表示月份。

(3)java.util.Datejava.util.Calendar中的所有属性都是可变的。

(4)SimpleDateTimeFormat是非线程安全的。

基于上述问题,在 Java 8 对日期进行了优化,首先是将日期和时间设计为不可变类型,就像String类型一样,这样就避免了多线程下对日期的修改导致的线程安全问题,每次对日期的操作都会生成一个新的日期对象;另外还把功能进一步细化了,对日期的运算更加便利,输出也更加人性化。

(2) 本地时间 / 日期

LocalDate、LocalTime、 LocalDateTime类的实例是不可变的对象,分别表示使用ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的日期或时间,并不包含当前的时间信息。也不包含与时区相关的信息。

常用方法:

方法名返回值类型解释
now()static ,LocalDate Time从默认时区的系统时钟获取当前日期
of(int year, int month, int dayOfMonth, int hour, int minute, int second)static,LocalDateTime从年月日时分秒获得LocalDATe Time的实例,将纳秒设置为零
plus(long amountToAdd, TemporalUnit unit)LocalDateTime返回此日期时间的副本,并添加指定的数量
get(TemporaField field)int从此日期时间获取指定字段的值为int
 		// 获取当前时间System.out.println(LocalDateTime.now());// 获取指定时间LocalDateTime of = LocalDateTime.of(2023, 3, 27, 17, 30, 18);System.out.println(of);// 加 plusSystem.out.println(of.plusMonths(1));// 减 minusSystem.out.println(of.minusMonths(3));// 获取指定给的年月日时分秒System.out.println(of.getDayOfMonth());System.out.println(of.getHour());

(3) 时间戳

时间戳是以Unix元年1970-01-01 00:00:00到某个时间之间的毫秒数。

		// 默认获取UTC时区(UTC:世界协调时间)Instant now = Instant.now();System.out.println(now);// 带偏移量的时间日期(如: UTC + 8)System.out.println(now.atOffset(ZoneOffset.ofHours(1)));// 转换成对应的毫秒值System.out.println(now.toEpochMilli());// 构建时间戳System.out.println(Instant.ofEpochSecond(60));

(4) 时间/日期差

  • Duration:计算两个时间之间的间隔
  • Period:计算两个日期之间的间隔
		Instant ins1 = Instant.now();Instant ins2 = Instant.now();Duration d = Duration.between(ins1, ins2);System.out.println(d.getSeconds()); // 秒System.out.println(d.getUnits()); // 时间戳LocalDate ld1 = LocalDate.of(2023, 9, 1);LocalDate ld2 = LocalDate.now();Period p = Period.between(ld2, ld1);System.out.println(p.getYears()); // 年System.out.println(p.toTotalMonths()); // 月

(5) 时间校正器

  • TemporalAdjuster:时间校正器。有时我们可能需要获取例如:将日期调整到下个周日等操作。
  • TemporalAdjusters:该类通过静态方法提供了大量的常用 TemporalAdjuster的实现

例如:获取下个周日

 LocalDate nextSunday = LocalDate.now().with(TemporaAdjusters.next(DayOfWeek.SUNDAY));

一些时间校正器的使用如下:

 		LocalDateTime t1 = LocalDateTime.now();System.out.println(t1);// 指定日期时间中的年月日LocalDateTime t2 = t1.withDayOfMonth(10);System.out.println(t2);// 指定时间校正器LocalDateTime t3 = t1.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));System.out.println(t3);// 自定义时间矫正器LocalDateTime t5 = t1.with(ta -> {LocalDateTime t4 = (LocalDateTime) ta;DayOfWeek dow = t4.getDayOfWeek();if (dow.equals(DayOfWeek.MONDAY)) {return t4.plusDays(6);} else {// 其他时间逻辑...return t4;}});System.out.println(t5);

(6) 时间格式化

  • DateTimeFormatter:格式化日期或时间
		//默认格式化DateTimeFormatter dtf1 = DateTimeFormatter.ISO_DATE_TIME;LocalDateTime ldt1 = LocalDateTime.now();String str1 = ldt1.format(dtf1);System.out.println(str1);//自定义格式化 ofPatternDateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");LocalDateTime ldt2 = LocalDateTime.now();String str2 = ldt2.format(dtf2);System.out.println(str2);//解析LocalDateTime newDate = LocalDateTime.parse(str1, dtf1);System.out.println(newDate);

(7) 时区

  • ZonedDate
  • ZonedTime
  • ZonedDateTime
		//查看支持的时区Set<String> set = ZoneId.getAvailableZoneIds();set.forEach(System.out::println);//指定时区LocalDateTime ldt1 = LocalDateTime.now(ZoneId.of("Europe/Tallinn"));System.out.println(ldt1);//在已构建好的日期时间上指定时区LocalDateTime ldt2 = LocalDateTime.now(ZoneId.of("Europe/Tallinn"));ZonedDateTime zdt1 = ldt2.atZone(ZoneId.of("Europe/Tallinn"));System.out.println(zdt1);

8、Annotations注解

在Java8中,对注解的改进主要有两点:类型注解和重复注解。

(1) 类型注解

新增ElementType.TYPE_USEElementType.TYPE_PARAMETER(在Target上)

新增的两个注释的程序元素类型 ElementType.TYPE_USEElementType.TYPE_PARAMETER 用来描述注解的新场合 。
ElementType.TYPE_PARAMETER 表示该注解能写在类型变量的声明语句中。
ElementType.TYPE_USE 表示该注解能写在使用类型的任何语句中(eg:声明语句、泛型和强制转换语句中的类型)。

类型注解的作用:

类型注解被用来支持在Java的程序中做强类型检查。配合第三方插件工具Checker Framework(注:此插件so easy,这里不介绍了),可以在编译的时候检测出runtime error(eg:UnsupportedOperationException; NumberFormatException;NullPointerException异常等都是runtime error),以提高代码质量。这就是类型注解的作用。

Note:

使用Checker Framework可以找到类型注解出现的地方并检查。

import checkers.nullness.quals.*;
public class TestDemo{void sample() {@NonNull Object my = new Object();}
}

编译上面的类,上面编译是通过的,但若修改代码:

@NonNull Object my = null;

但若不想使用类型注解检测出来错误,则不需要processor,正常javac TestDemo.java是可以通过编译的,但是运行时会报 NullPointerException 异常。

为了能在编译期间就自动检查出这类异常,可以通过类型注解结合 Checker Framework 提前排查出来错误异常。

注意java 5,6,7版本是不支持注解@NonNull,但checker framework 有个向下兼容的解决方案,就是将类型注解@NonNull 用/**/注释起来。

import checkers.nullness.quals.*;
public class TestDemo{void sample() {/*@NonNull*/ Object my = null;}
}

这样javac编译器就会忽略掉注释块,但用checker framework里面的javac编译器同样能够检测出@NonNull错误。
通过 类型注解 + checker framework 可以在编译时就找到runtime error。

(2) 重复注解

允许在同一声明类型(类,属性,或方法)上多次使用同一个注解。

Java8以前的版本使用注解有一个限制是相同的注解在同一位置只能使用一次,不能使用多次。Java 8 引入了重复注解机制,这样相同的注解可以在同一地方使用多次。重复注解机制本身必须用 @Repeatable 注解。

实际上,重复注解不是一个语言上的改变,只是编译器层面的改动,技术层面仍然是一样的。

(1)定义一个注解:

@Repeatable(MyAnnotations.class)
// TYPE_PARAMETER 类型参数
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, TYPE_PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {String value() default "java";
}

(2)定义一个注解容器

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotations {MyAnnotation[] value();
}

(3)使用

	@MyAnnotation("hello")@MyAnnotation("java")public static void show(@MyAnnotation("abc") String str) {System.out.println(str);}

相关文章:

JDK8新特性详解

☆* o(≧▽≦)o *☆嗨~我是小奥&#x1f379; &#x1f4c4;&#x1f4c4;&#x1f4c4;个人博客&#xff1a;小奥的博客 &#x1f4c4;&#x1f4c4;&#x1f4c4;CSDN&#xff1a;个人CSDN &#x1f4d9;&#x1f4d9;&#x1f4d9;Github&#xff1a;传送门 &#x1f4c5;&a…...

ELK+Filebeat 部署实验

Filebeat是轻量级的开源日志文件数据搜集器。通常在需要采集数据的客户端安装 Filebeat&#xff0c;并指定目录与日志格式&#xff0c;Filebeat 就能快速收集数据&#xff0c;并发送给 logstash 进行解析&#xff0c;或是直接发给 Elasticsearch 存储&#xff0c;性能上相比运行…...

利用wireshark lua扩展能力增加自定义解析器[注释解读版]

前言 Wireshark提供了lua扩展能力&#xff0c;可以定制一些Listner和Dissector&#xff0c;用于一些自定义的使用场景&#xff0c;例如: lua插件适应场景Listener报文统计、内容抽取等Dissector协议树解析&#xff0c;在wireshark中立等可看 已在以前的文档中积累了对于List…...

GPT-5不叫GPT-5?下一代模型会有哪些新功能?

OpenAI首席执行官奥特曼在上周三达沃斯论坛接受媒体采访时表示&#xff0c;他现在的首要任务就是推出下一代大模型&#xff0c;这款模型不一定会命名GPT-5。虽然GPT-5的商标早已经注册。 如果GPT-4目前解决了人类任务的10%&#xff0c;GPT-5应该是15%或者20%。 OpenAI从去年开…...

2024.1.23(347.前k个高频元素)

2024.1.23(347.前k个高频元素) 思路 这道题目主要涉及到如下三块内容&#xff1a; 1.要统计元素出现频率 2.对频率排序 3.找出前K个高频元素 首先统计元素出现的频率&#xff0c;这一类的问题可以使用map来进行统计。 然后是对频率进行排序&#xff0c;这里我们可以使用一种…...

MySQL对数据库的操作

前腰&#xff1a;本节只是的数据库本身进行增删查改、备份、恢复等操作&#xff0c;而不是对数据库内的数据表做操作&#xff0c;还请您区分好这两点。 1.创建数据库 # 创建数据库的语法形式 CREATE DATABASE [IF NOT EXISTS] database_name [create_specification]# 大写的是…...

解决Unity WebGLInput插件全屏输入的问题

unity webgl的中文输入插件WebglInput在全屏的时候会出现无法输入中文/输入的英文会字母出现在光标后面/什么都输入不了的等无法正常使用的情况。 插件官网作者给出了unity的2017&#xff0c;2018&#xff0c;2019版本的全屏输入解决方法。 最新插件下载地址&#xff1a;http…...

Android14实战:调整A2DP音量曲线(五十三)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只…...

vector讲解

在学习玩string后我们开始学习vector&#xff0c;本篇博客将对vector进行简单的介绍&#xff0c;还会对vector一些常用的函数进行讲解 vector的介绍 实际上vector就是一个数组的数据结构&#xff0c;但是vector是由C编写而成的&#xff0c;他和数组也有本质上的区别&#xff…...

nvm 配置淘宝镜像失效,以及安装node后 npm-v 无效

win11 nvm版本 1.1.4 和1.1.7和1.1.12&#xff08;目前最新版本24年 一月二十三日&#xff09; 以上nvm版本都会出现一下问题&#xff0c; 从https://github.com/coreybutler/nvm-windows/releases 下载nvm安装包如下图 傻瓜式安装后&#xff0c;不用去配置环境变量&#…...

【Android Gradle 插件】Gradle 基础配置 ④ ( Gradle Wrapper 配置作用 | Gradle 下载的依赖库存放位置 )

一、Gradle Wrapper 配置作用 gradle wrapperdistributionBaseGRADLE_USER_HOME distributionPathwrapper/dists distributionUrlhttps\://services.gradle.org/distributions/gradle-6.7.1-bin.zip zipStoreBaseGRADLE_USER_HOME zipStorePathwrapper/distsGradle Wrapper 配…...

Deepin_Ubuntu_查看树形目录结构(tree)

Linux系统&#xff08;Deepin、Ubuntu&#xff09;中&#xff0c;可以使用tree命令来查看树形目录结构&#xff0c;下面是一些示例&#xff1a; 查看当前目录的树形结构&#xff1a; tree查看指定目录的树形结构&#xff0c;例如/etc/X11/fonts目录&#xff1a; tree /etc/X…...

Java Excel分割成许多小文件

最近在处理excel&#xff0c;数据很多&#xff0c;需要将excel拆分成许多小块&#xff0c;并保留原来的格式&#xff0c;于是写了该算法&#xff0c;并能保留原来的样式&#xff0c;使用很简单&#xff1a; Sheet splitSheet ExcelUtil.split(sheet, 0, 20, 5, 8); 传入开始…...

【心得】java从CC1链入门CC链个人笔记

来劲了&#xff0c;感觉离真正的CTF又近了一步。 本文仅从一个萌新的角度去谈&#xff0c;如有纰漏&#xff0c;纯属蒟蒻。 目录 CC链概念 CC链学习前置知识 CC1链 Version1 Version2 Version3 CC链概念 CC链 Commons Collections apache组织发布的开源库 里面主要对…...

Django migration 新增外键的坑

TL;DR 永远不要相信 makemigrations&#xff01; migrate 之前一定好好看看 migrate 了啥东西&#xff0c;必要时手动修改生成的 migrate 文件。 最好把db的更新与服务代码更新解耦 场景 先描述下场景&#xff1a; 现在有两个表&#xff0c;一个是 question&#xff0c;一…...

相关系数(皮尔逊相关系数和斯皮尔曼相关系数)

本文借鉴了数学建模清风老师的课件与思路&#xff0c;可以点击查看链接查看清风老师视频讲解&#xff1a;5.1 对数据进行描述性统计以及皮尔逊相关系数的计算方法_哔哩哔哩_bilibili 注&#xff1a;直接先看 &#xff08; 三、两个相关系数系数的比较 &#xff09; 部分&#x…...

了解 Vite 插件

众所周知 Vite 是基于 Rollup 的构建工具&#xff0c;Vite 插件为了优化、扩展项目构建系统功能的工具。 比如 vite-plugin-eslint 为我们提供了代码分析的功能&#xff0c;帮助我们在开发过程中的风格一致性。 简单示例 本文中的示例是基于 Vite Vue3.x TypeScript 来实现…...

算法竞赛基础:C++双向链表的结构和实现(普通链表、List、静态链表)

算法竞赛基础&#xff1a;双向链表 本文将会介绍在算法竞赛中双向链表的几种使用方式&#xff0c;适合有一定基础的人阅读。 双向链表的结构 一般来说&#xff0c;普通的链表结构是这样的&#xff1a; struct node {int num;node *next; }next指针指向下一个链表&#xff…...

openssl3.2/test/certs - 019 - ca-nonca trust variants: +serverAuth, +anyEKU

文章目录 openssl3.2/test/certs - 019 - ca-nonca trust variants: serverAuth, anyEKU概述笔记 ca-nonca.pem from exp 016openssl3.2/test/certs - 019 - ca-nonca trust variants: serverAuth, anyEKUEND openssl3.2/test/certs - 019 - ca-nonca trust variants: serverAu…...

Unity SRP 管线【第五讲:URP烘培光照】

本节&#xff0c;我们将跟随数据流向讲解UEP管线中的烘培光照。 文章目录 一、URP烘培光照1. 搭建场景2. 烘培光照参数设置MixedLight光照设置&#xff1a;直观感受 Lightmapping Settings参数设置&#xff1a; 3. 我们如何记录次表面光源颜色首先我们提取出相关URP代码&#…...

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

OpenLayers 可视化之热力图

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 热力图&#xff08;Heatmap&#xff09;又叫热点图&#xff0c;是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

PHP和Node.js哪个更爽?

先说结论&#xff0c;rust完胜。 php&#xff1a;laravel&#xff0c;swoole&#xff0c;webman&#xff0c;最开始在苏宁的时候写了几年php&#xff0c;当时觉得php真的是世界上最好的语言&#xff0c;因为当初活在舒适圈里&#xff0c;不愿意跳出来&#xff0c;就好比当初活在…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

BLEU评分:机器翻译质量评估的黄金标准

BLEU评分&#xff1a;机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域&#xff0c;衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标&#xff0c;自2002年由IBM的Kishore Papineni等人提出以来&#xff0c;…...

LOOI机器人的技术实现解析:从手势识别到边缘检测

LOOI机器人作为一款创新的AI硬件产品&#xff0c;通过将智能手机转变为具有情感交互能力的桌面机器人&#xff0c;展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家&#xff0c;我将全面解析LOOI的技术实现架构&#xff0c;特别是其手势识别、物体识别和环境…...

PostgreSQL 与 SQL 基础:为 Fast API 打下数据基础

在构建任何动态、数据驱动的Web API时&#xff0c;一个稳定高效的数据存储方案是不可或缺的。对于使用Python FastAPI的开发者来说&#xff0c;深入理解关系型数据库的工作原理、掌握SQL这门与数据库“对话”的语言&#xff0c;以及学会如何在Python中操作数据库&#xff0c;是…...