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消费型接口 | T | void | 对类型为T的对象应用操作:viod accept(T t) |
| Supplier提供型接口 | 无 | T | 返回类型为T的对象:T get() |
| Function<T, R>函数型接口 | T | R | 对类型为T的对象应用操作,并返回结果为R类型的对象:R apply(T t) |
| Predicate断言型接口 | T | boolean | 确定类型为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.Date 和 java.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) 时区
ZonedDateZonedTimeZonedDateTime
//查看支持的时区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_USE 和ElementType.TYPE_PARAMETER(在Target上)
新增的两个注释的程序元素类型 ElementType.TYPE_USE 和 ElementType.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 *☆嗨~我是小奥🍹 📄📄📄个人博客:小奥的博客 📄📄📄CSDN:个人CSDN 📙📙📙Github:传送门 📅&a…...
ELK+Filebeat 部署实验
Filebeat是轻量级的开源日志文件数据搜集器。通常在需要采集数据的客户端安装 Filebeat,并指定目录与日志格式,Filebeat 就能快速收集数据,并发送给 logstash 进行解析,或是直接发给 Elasticsearch 存储,性能上相比运行…...
利用wireshark lua扩展能力增加自定义解析器[注释解读版]
前言 Wireshark提供了lua扩展能力,可以定制一些Listner和Dissector,用于一些自定义的使用场景,例如: lua插件适应场景Listener报文统计、内容抽取等Dissector协议树解析,在wireshark中立等可看 已在以前的文档中积累了对于List…...
GPT-5不叫GPT-5?下一代模型会有哪些新功能?
OpenAI首席执行官奥特曼在上周三达沃斯论坛接受媒体采访时表示,他现在的首要任务就是推出下一代大模型,这款模型不一定会命名GPT-5。虽然GPT-5的商标早已经注册。 如果GPT-4目前解决了人类任务的10%,GPT-5应该是15%或者20%。 OpenAI从去年开…...
2024.1.23(347.前k个高频元素)
2024.1.23(347.前k个高频元素) 思路 这道题目主要涉及到如下三块内容: 1.要统计元素出现频率 2.对频率排序 3.找出前K个高频元素 首先统计元素出现的频率,这一类的问题可以使用map来进行统计。 然后是对频率进行排序,这里我们可以使用一种…...
MySQL对数据库的操作
前腰:本节只是的数据库本身进行增删查改、备份、恢复等操作,而不是对数据库内的数据表做操作,还请您区分好这两点。 1.创建数据库 # 创建数据库的语法形式 CREATE DATABASE [IF NOT EXISTS] database_name [create_specification]# 大写的是…...
解决Unity WebGLInput插件全屏输入的问题
unity webgl的中文输入插件WebglInput在全屏的时候会出现无法输入中文/输入的英文会字母出现在光标后面/什么都输入不了的等无法正常使用的情况。 插件官网作者给出了unity的2017,2018,2019版本的全屏输入解决方法。 最新插件下载地址:http…...
Android14实战:调整A2DP音量曲线(五十三)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只…...
vector讲解
在学习玩string后我们开始学习vector,本篇博客将对vector进行简单的介绍,还会对vector一些常用的函数进行讲解 vector的介绍 实际上vector就是一个数组的数据结构,但是vector是由C编写而成的,他和数组也有本质上的区别ÿ…...
nvm 配置淘宝镜像失效,以及安装node后 npm-v 无效
win11 nvm版本 1.1.4 和1.1.7和1.1.12(目前最新版本24年 一月二十三日) 以上nvm版本都会出现一下问题, 从https://github.com/coreybutler/nvm-windows/releases 下载nvm安装包如下图 傻瓜式安装后,不用去配置环境变量&#…...
【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系统(Deepin、Ubuntu)中,可以使用tree命令来查看树形目录结构,下面是一些示例: 查看当前目录的树形结构: tree查看指定目录的树形结构,例如/etc/X11/fonts目录: tree /etc/X…...
Java Excel分割成许多小文件
最近在处理excel,数据很多,需要将excel拆分成许多小块,并保留原来的格式,于是写了该算法,并能保留原来的样式,使用很简单: Sheet splitSheet ExcelUtil.split(sheet, 0, 20, 5, 8); 传入开始…...
【心得】java从CC1链入门CC链个人笔记
来劲了,感觉离真正的CTF又近了一步。 本文仅从一个萌新的角度去谈,如有纰漏,纯属蒟蒻。 目录 CC链概念 CC链学习前置知识 CC1链 Version1 Version2 Version3 CC链概念 CC链 Commons Collections apache组织发布的开源库 里面主要对…...
Django migration 新增外键的坑
TL;DR 永远不要相信 makemigrations! migrate 之前一定好好看看 migrate 了啥东西,必要时手动修改生成的 migrate 文件。 最好把db的更新与服务代码更新解耦 场景 先描述下场景: 现在有两个表,一个是 question,一…...
相关系数(皮尔逊相关系数和斯皮尔曼相关系数)
本文借鉴了数学建模清风老师的课件与思路,可以点击查看链接查看清风老师视频讲解:5.1 对数据进行描述性统计以及皮尔逊相关系数的计算方法_哔哩哔哩_bilibili 注:直接先看 ( 三、两个相关系数系数的比较 ) 部分&#x…...
了解 Vite 插件
众所周知 Vite 是基于 Rollup 的构建工具,Vite 插件为了优化、扩展项目构建系统功能的工具。 比如 vite-plugin-eslint 为我们提供了代码分析的功能,帮助我们在开发过程中的风格一致性。 简单示例 本文中的示例是基于 Vite Vue3.x TypeScript 来实现…...
算法竞赛基础:C++双向链表的结构和实现(普通链表、List、静态链表)
算法竞赛基础:双向链表 本文将会介绍在算法竞赛中双向链表的几种使用方式,适合有一定基础的人阅读。 双向链表的结构 一般来说,普通的链表结构是这样的: struct node {int num;node *next; }next指针指向下一个链表ÿ…...
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烘培光照】
本节,我们将跟随数据流向讲解UEP管线中的烘培光照。 文章目录 一、URP烘培光照1. 搭建场景2. 烘培光照参数设置MixedLight光照设置:直观感受 Lightmapping Settings参数设置: 3. 我们如何记录次表面光源颜色首先我们提取出相关URP代码&#…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...
免费数学几何作图web平台
光锐软件免费数学工具,maths,数学制图,数学作图,几何作图,几何,AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...
[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.
ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #:…...
