public interface JDK8Interface {
// 1. 定义属性,默认修饰符为: public static final(无法修改)
int color = 10;
// 2. 定义方法,默认修饰符为:public abstract(无法修改)
void show();
// 3. jdk8新特性,定义接口默认方法,默认加了public修饰(无法修改)
default void defaultMethod(){
System.out.println("defaultMethod");
}
// 4. jdk8新特性,定义接口静态方法,可以通过类名.的方式调用,默认加了public修饰(无法修改)
static void staticMethod() {
System.out.println("staticMethod");
}
}
public class JDK8InterfaceImpl implements JDK8Interface {
@Override
public void show() {
System.out.println("show");
}
}
public class Test {
public static void main(String[] args) {
JDK8InterfaceImpl jdk8Interface = new JDK8InterfaceImpl();
// 1. 调用实现的方法
jdk8Interface.show();
// 2. 调用接口的default方法
jdk8Interface.defaultMethod();
// 3. 调用接口的静态方法, 不可以通过实现类的对象调用
JDK8Interface.staticMethod();
}
}
lambda表达式是为了能够简化实现匿名内部类的代码。
public class Test {
public static void main(String[] args) {
// 1. 匿名内部类的方式,一共6行代码
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "-- 线程正在运行 --");
}
}).start();
// 2.lambda表达式的方式
new Thread(() -> System.out.println(Thread.currentThread().getName() + "-- 线程正在运行 --")).start();
}
}
写在方法中作为一个函数式接口的返回值
成为方法的参数或局部变量(前提是类型为一个函数式接口)
该接口中必须有且只能有一个抽象方法
可以在接口中添加@FuncationInterface(函数式接口),一旦加了该注释,那么该接口中就必须符合上一点的规范。
该接口中定义Object类中的方法
该接口中可以定义default和static方法
lambda表达式的三个组成部分 : () -> {}
1. ( ) 参数列表,不需要写参数类型
2. -> 参数列表与方法体的连接符
3. { } 方法体
当参数列表的参数数量为1时候,可以省略小括号
当方法体只有一条语句时,可以省略大括号
匿名内部类的类型可以是类、抽象类、接口
lambda表达式的类型只能是接口
匿名内部类的类型可以有多个抽象方法
lambda表达式的类型有且只能有一个抽象方法
匿名内部类
lambda表达式
会在当前类中创建一个方法,其中包含我们需要运行的代码
会创建一个类来实现该接口,该接口会调用在当前类中生成的方法
- Consumer<T> : void accept(T t) 消费型接口
- Supplier<T> : T get() 提供型接口
- Function<T,R> : R apply(T t) 函数型接口
- Predicate<T> : boolean test(T t) 断言型接口
对象::成员方法名
// Consumer的方法: void accept(T t);因为用了泛型,所以T相当于String
// println方法:public void println(String x) {}
Consumer<String> consumer1 = s -> System.out.println(s);
Consumer<String> consumer2 = System.out::println;
// Comparator的方法:int compare(T o1, T o2);因为用了泛型,所以T相当于String
// Integer的方法:public int compareTo(Integer anotherInteger);
Comparator<Integer> comparator1 = (o1,o2) -> o1 - o2;
Comparator<Integer> comparator2 = Integer::compareTo;
// BiFunction的方法:R apply(T t, U u);由于传递了泛型的参数类型,所以T和U都相当于String,R相当于Boolean
// equals方法:public boolean equals(Object anObject);
public class Test {
public static void main(String[] args) {
// BiFunction<String,String,Boolean> bif = (x,y) -> x.equals(y);
BiFunction<String,String,Boolean> bif = String::equals;
Boolean apply = bif.apply("abc", "abc");
System.out.println(apply);
}
}
平时我们操作集合获取其中的某些元素时,总是不可避免的需要对集合进行遍历遍历再遍历,这就使得代码量不断扩大。而stream流可以帮我们解决这一系列问题,让我们的代码变得更简洁,操作也更加方便。
stream流的思想与io中的输入输出流不是一个概念,这个stream流指的是将数据像流水线一样进行加工处理,最终再给予最终的结果。
Stream流中的方法共分为两类,分别为终结方法(返回最终结果)与非终结方法(返回一个处理后的Stream流)。若是一个Stream流没有执行终结方法,则非终结方法不会被执行。
一个Stream流只能被操作一次(!!!),意思是只要一个流你调用过任何方法,那么该流就无法被再次使用(该流调用后返回的流除外),会抛出异常:IllegalStateException: stream has already been operated upon or closed
public class StreamTest {
public static void main(String[] args) {
// 1. 通过Collection接口中的默认方法stream()获取,Collection接口的子类有List和Set
Stream<String> stream1 = new ArrayList<String>().stream();
Stream<String> stream2 = new HashSet<String>().stream();
// 2. 通过Stream接口的静态方法 Stream<T> of(T t)
Stream<Integer> stream3 = Stream.of(1235);
// 3. 通过Stream接口的静态方法 Stream<T> of(T... values),
// 注意:如果直接传递一个数组的话,不能为基本数据类型的数组
Stream<Integer> stream4 = Stream.of(5, 98, 55, 11, 77, 35, 36);
}
}
forEach的方法定义如下:
void forEach(Consumer<? super T> action);
forEach方法的基本使用
Stream<String> stream = Arrays.asList("张三", "李四", "王五", "赵六").stream();
stream.forEach((s) -> System.out.println(s));
张三
李四
王五
赵六
count方法的定义如下
long count();
count方法的基本使用
Stream<String> stream = Arrays.asList("张三", "李四", "王五", "赵六").stream();
long count = stream.count();
System.out.println(count); // 结果为4
方法的定义如下
Stream<T> filter(Predicate<? super T> predicate);
filter方法的基本使用
Stream<String> stream = Arrays.asList("张三峰", "李四", "王五米", "赵六").stream();
// 过滤出所有字符串长度为3的数据并输出
stream.filter(s -> s.length() == 3).forEach(System.out::println);
Stream<T> limit(long maxSize);Stream<T> skip(long n); Stream<String> stream = Arrays.asList("张三峰", "李四", "王五米", "赵六").stream();
// limit:获取流中的前2个元素并输出,结果为:张三峰、李四
stream.limit(2).forEach(System.out::println);
Stream<String> stream = Arrays.asList("张三峰", "李四", "王五米", "赵六").stream();
// skip: 跳过流中的前2个元素,只获取之后的元素,结果为:王五米、赵六
stream.skip(2).forEach(System.out::println);
boolean allMatch(Predicate<? super T> predicate);boolean anyMatch(Predicate<? super T> predicate);boolean noneMatch(Predicate<? super T> predicate); Stream<String> stream = Arrays.asList("张三峰", "李四", "王五米", "赵六").stream();
// 1. 判断Stream流中的字符串元素是否全都满足长度为3,满足返回true,否则为false
// System.out.println(stream.allMatch(s -> s.length() == 3)); // false
// 2. 判断Stream流中的字符串元素是否有任意一个满足长度为3,满足返回true,否则为false
// System.out.println(stream.anyMatch(s -> s.length() == 3)); // true
// 3. 判断Stream流中的字符串元素是否全都 不满足长度为3,满足返回true,否则为false
System.out.println(stream.noneMatch(s -> s.length() == 3)); // fasle
Optional<T> findFirst();Optional<T> findAny(); 串行时基本返回第一个元素,并行就未必了。 Stream<String> stream = Arrays.asList("张三峰", "李四", "王五米", "赵六").stream();
// 1. 获取Stream流中的第一个元素
// Optional<String> first = stream.findFirst();
// System.out.println(first.get());
// 2. 获取Stream流中的任意一个元素, 串行、或者数据量小时可能会一直返回第一个元素
Optional<String> any = stream.findFirst();
System.out.println(any.get());
方法定义
Optional<T> max(Comparator<? super T> comparator);
Optional<T> min(Comparator<? super T> comparator);
max的基本使用
Stream<String> stream = Arrays.asList("z张三峰", "b李四", "a王五米", "c赵六").stream();
Optional<String> max = stream.max((s1, s2) -> s1.compareTo(s2));
System.out.println(max.get()); // 输出结果为z张三峰
Stream<Integer> stream = Arrays.asList(23, 44, 95, 11).stream();
Optional<Integer> min = stream.min((i1, i2) -> i1.compareTo(i2));
System.out.println(min.get()); // 输出结果为11
T reduce(T identity, BinaryOperator<T> accumulator);
Optional<T> reduce(BinaryOperator<T> accumulator);
<U> U reduce(U identity,BiFunction<U, ? super T, U> accumulator,BinaryOperator<U> combiner); 暂不演示
- 解释:第一个参数为初始值,第二个函数化接口父类中的接口及方法的定义如下:
- 接口:`public interface BinaryOperator<T> extends BiFunction<T,T,T>`
- 父类BiFunction中的方法:`R apply(T t, U u);`
- 因此可以看出,是传入2个同类型的参数,再返回一个相同类型的参数。
Stream<Integer> stream = Arrays.asList(1, 2, 3, 4).stream();
// 获取Stream流中所有整数之和
// 1. 使用 T reduce(T identity, BinaryOperator<T> accumulator) 实现数据的增加统计
// 这里的x值为0,每次都会把x + y 的值赋给x
// 其中的y就是每次遍历出来的整数
// Integer sum = stream.reduce(2, (x, y) -> x + y);
// System.out.println(sum); // 12
// 2. 使用 Optional<T> reduce(BinaryOperator<T> accumulator) 实现数据的增加统计
Optional<Integer> sum = stream.reduce((x, y) -> x + y);
System.out.println(sum.get()); // 10
<R> Stream<R> map(Function<? super T, ? extends R> mapper); Stream<Integer> stream = Arrays.asList(1, 2, 3, 4).stream();
// 将strem流中的数据类型转换为String
stream.map((i) -> String.valueOf(i)).forEach(s -> {
System.out.println("当前的数据类型为:" + s.getClass().getSimpleName()); // String
});
存在的意义:会提高处理Int数据的速度,当Stream流中不仅是Int数据且数据量大时可以考虑。
方法定义
IntStream mapToInt(ToIntFunction<? super T> mapper);
mapToInt的基本使用
Stream<String> stream1 = Arrays.asList("1", "2", "3", "4").stream();
// 将Stream流转换为IntStream流
IntStream intStream = stream1.mapToInt(s -> Integer.parseInt(s));
intStream.forEach(System.out::println);
方法定义
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
map的基本使用
Stream<Integer> stream = Arrays.asList(1, 2, 3, 4).stream();
// 将strem流中的数据类型转换为String
stream.map((i) -> String.valueOf(i)).forEach(s -> {
System.out.println("当前的数据类型为:" + s.getClass().getSimpleName()); // String
});
<R, A> R collect(Collector<? super T, A, R> collector);<R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner); 暂不演示 Stream<String> stream = Arrays.asList("1", "2", "3", "4").stream();
// 1. 收集到List集合中
// List<String> collect = stream.collect(Collectors.toList());
// 2. 收集到ArrayList集合中
ArrayList<String> collect = stream.collect(Collectors.toCollection(() -> new ArrayList<>()));
Stream<String> stream = Arrays.asList("1", "2", "3", "4").stream();
// 1. 收集到Set集合中
// Set<String> collect = stream.collect(Collectors.toSet());
// 2. 收集到HashSet集合中
HashSet<String> collect = stream.collect(Collectors.toCollection(() -> new HashSet<>()));
Stream<String> stream = Arrays.asList("aa", "cc", "bb", "dd").stream();
// 1. 获取Object类型的数组
// Object[] objects = stream.toArray();
// 2. 获取任意类型的数组,只能是引用类型
// String[] strings = stream.toArray(s -> new String[4]); // 必须手动指定长度
String[] strings = stream.toArray(String[]::new);
当我们使用Stream流处理数据后,可以像数据库的聚合函数一样对数据的某个字段进行聚合操作。最大值、最小值、求和、平均值、统计数量。
Stream<Integer> stream = Arrays.asList(1, 2, 3, 4).stream();
// 1. 最大值
Optional<Integer> max = stream.collect(Collectors.maxBy((i1, i2) -> Integer.compare(i1, i2)));
System.out.println(max.get()); // 4
Stream<Integer> stream = Arrays.asList(1, 2, 3, 4).stream();
// 2. 最小值
Optional<Integer> min = stream.collect(Collectors.minBy((i1, i2) -> Integer.compare(i1, i2)));
System.out.println(min.get()); // 1
Stream<Integer> stream = Arrays.asList(1, 2, 3, 4).stream();
// 3. 求和
int sum = stream.collect(Collectors.summingInt(i -> i));
System.out.println(sum); // 10
Stream<Integer> stream = Arrays.asList(1, 2, 3, 4).stream();
// 4. 平均值
Double average = stream.collect(Collectors.averagingInt(i -> i));
System.out.println(average); // 2.5
Stream<Integer> stream = Arrays.asList(1, 2, 3, 4).stream();
// 5. 统计数量
Long count = stream.collect(Collectors.counting());
System.out.println(count); // 4
ArrayList<Person> list = new ArrayList<>();
list.add(new Person("张三",15));
list.add(new Person("李四",26));
list.add(new Person("王五",15));
list.add(new Person("名吉",15));
list.add(new Person("赵六",12));
Stream<Person> stream = list.stream();
// 1. 按照年龄进行分组
Map<Integer, List<Person>> ageGroupList = stream.collect(Collectors.groupingBy(p -> p.getAge()));
ageGroupList.forEach((k, v) -> System.out.println("年龄为:" + k + ",该组人员有:" + v));

// 1. 按照年龄进行分组、再将分组后的数据按照姓名分组
Map<Integer, Map<String, List<Person>>> groups = stream.collect
(
Collectors.groupingBy
(
p -> p.getAge(),
Collectors.groupingBy(p -> p.getName())
)
);
groups.forEach((k,v) -> {
System.out.println("按照年龄分组:" + k + ",分组内容为:" + v);
v.forEach((k2,v2) -> System.out.println("按照姓名分组:" + k2 + ",分组内容为:" + v2));
System.out.println("-----------------------------------");
});
ArrayList<Person> list = new ArrayList<>();
list.add(new Person("张三",15));
list.add(new Person("李四",26));
list.add(new Person("王五",15));
list.add(new Person("名吉",15));
list.add(new Person("赵六",12));
Stream<Person> stream = list.stream();
// 1. 按照年龄进行分组,并统计有多少人
Map<Integer, Long> collect = stream.collect(Collectors.groupingBy(p -> p.getAge(), Collectors.counting()));
collect.forEach((k, v) -> System.out.println("年龄为:" + k + ",该组人数有:" + v));
ArrayList<Person> list = new ArrayList<>();
list.add(new Person("张三",15));
list.add(new Person("李四",26));
list.add(new Person("王五",15));
list.add(new Person("张三",15));
list.add(new Person("赵六",12));
Stream<Person> stream = list.stream();
// 将年龄小于15岁的与年龄不小于15岁的人分为2组,分别为true组和false组
Map<Boolean, List<Person>> collect = stream.collect(Collectors.partitioningBy(p -> p.getAge() < 15));
collect.forEach((k,v) -> System.out.println(k + "组的成员有:" + v));
Stream串行流:单个线程执行Stream流中的处理操作
Stream并行流:多个线程执行Stream流中的处理操作(forkjoin框架,任务窃取算法)
Stream<Integer> parallelStream = Arrays.asList(1, 4, 5, 1, 6).parallelStream();
Stream<Integer> stream = Arrays.asList(1, 4, 5, 1, 6).stream();
// 转换为一个并行流
Stream<Integer> parallelStream = stream.parallel();
// 1. 创建一个ArrayList<Integer> 集合,往里面存入1000个数据
ArrayList<Integer> oldList = new ArrayList<>();
for (int i = 1; i <= 1000; i++) {
oldList.add(i);
}
// 2. 获取一个并行流
Stream<Integer> parallelStream = oldList.parallelStream();
// 3. 创建一个新的集合
ArrayList<Integer> newList = new ArrayList<>();
// 4. 使用并行流将oldList集合中的数据添加到newList集合中
parallelStream.forEach(i -> newList.add(i));
// 5. 输出newList集合的元素数量
System.out.println(newList.size()); // 数量不定的变换,或者直接抛出异常,出现了线程安全问题
}
// 4. 使用并行流将oldList集合中的数据添加到newList集合中
// 这里使用了当前的测试类.class作为同步锁
parallelStream.forEach(i -> {
synchronized (StreamTest.class) {
newList.add(i);
}
});
// 3. 创建一个新的集合
Vector<Integer> newList = new Vector<>();
// 3. 创建一个新的集合
ArrayList<Integer> newList1 = new ArrayList<>();
List<Integer> newList = Collections.synchronizedList(newList1);
ArrayList<Integer> newList = parallelStream.collect(Collectors.toCollection(() -> new ArrayList<>()));
或者
Integer[] integers = parallelStream.toArray(Integer[]::new);
public static <T> Optional<T> of(T value)
public static <T> Optional<T> ofNullable(T value)
public static<T> Optional<T> empty()
// 1. 通过Optional类的静态方法of创建一个Optional对象,不能传null
Optional<Person> op1 = Optional.of(new Person("zhangsan", 15));
// 2. 通过Optional类的静态方法ofNullable创建一个Optional对象,可以传null空对象
Optional<Person> op2 = Optional.ofNullable(null);
// 3. 通过Optional类的静态方法empty()获取一个为空对象的Optional对象
Optional<Object> op3 = Optional.empty();
获取Optional类中存储的对象,如果为null则会抛出异常
Optional<Person> op1 = Optional.of(new Person("zhangsan", 15));
Person person = op1.get();
System.out.println(person); // Person{name='zhangsan', age=15}
判断存储的对象是否包含值,包含返回true、不包含返回flase
Optional<Person> op1 = Optional.ofNullable(null);
boolean present = op1.isPresent();
System.out.println(present); // false
如果Optional中的对象为null,返回该方法传递的值,否则返回原Optional对象中的值
Optional<Person> op1 = Optional.ofNullable(null);
Person person = op1.orElse(new Person("zhang", 15));
System.out.println(person); // new Person("zhang", 15)
同上方法一致,不过是将T换成了一个函数式接口
Optional<Person> op1 = Optional.ofNullable(new Person("lis",11));
Person person = op1.orElseGet(() -> new Person("lisi", 55));
System.out.println(person); // Person{name='lis', age=11}
如果Optional中的对象不为空,则执行一段代码
Optional<Person> op1 = Optional.ofNullable(null);
// 当对象为null时不执行
op1.ifPresent(p -> System.out.println("今天天气真好" + p));
判断Optional中的对象是否满足条件,满足则返回该对象,不满足返回null
Optional<Person> op1 = Optional.ofNullable(null);
// 当对象为null时不执行
op1.ifPresent(p -> System.out.println("今天天气真好" + p));
将Optional中的对象转换为另一个类型
Optional<Person> op1 = Optional.ofNullable(new Person(null,15));
// 返回的Optional中的对象值为null
Optional<String> opStr = op1.map(p -> p.getName());
// 返回的Optional中的对象值为15
Optional<Integer> opInt = op1.map(p -> p.getAge());
/**
* @author codeStars
* @date 2022/8/6 10:13
* 返回Person对象中的name并且转换为大写,如果name值为空,则返回 name值为null
*/
public class StreamTest {
public static void main(String[] args) {
Optional<Person> op1 = Optional.ofNullable(new Person(null,15));
String name = getUpperCaseName(op1);
System.out.println(name);
}
/**
* 返回Person对象中的name并且转换为大写,如果name值为空,则返回 name值为null
* @param op1
* @return
*/
private static String getUpperCaseName(Optional<Person> op1) {
String msg = "";
if(op1.isPresent()) {
/*
注意这里的toUpperCase不会抛空指针异常。因为op1.map(Person::getName)执行后,
得到的Optional中的对象就已经为空对象了
再调用map方法时,会先判断Optional中的对象是否为空对象
源码如下:
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
所以如果Person中的name为空的话,根本就执行不到toUpperCase
*/
msg = op1.map(Person::getName).map(String::toUpperCase).orElse("name值为null");
}
return msg;
}
}
class Person {
private String name;
private int age;
// 省略 get/set/toString/全参construction
}
以前的日期时间API设计不合理
在java.sql中有一个Date类,用来存储年月日
以前的Date是线程不安全的,导致在多线程情况下出现数据异常等问题。
新的API解决了线程安全问题,因为它的每一个日期时间类都是固定不变的,每次对其进行任何修改时,都会返回一个新的日期时间类,因此可以保证在多线程的情况下不会出现线程安全问题。
// 获取指定的日期
LocalDate localDate = LocalDate.of(2022, 8, 5);
// 获取当前的日期
LocalDate nowDate = LocalDate.now();
// 1. 获取年
int year = localDate.getYear();
// 2. 获取月
int month = localDate.getMonth().getValue();
// 3. 获取日
int dayOfMonth = localDate.getDayOfMonth();
System.out.println("year = " + year);
System.out.println("month = " + month);
System.out.println("dayOfMonth = " + dayOfMonth);
// 获取指定的时间
LocalTime localTime = LocalTime.of(21,24,50,716000000);
// 获取当前的时间
LocalTime nowTime = LocalTime.now();
// 1. 获取小时
int hour = localTime.getHour();
// 2. 获取分钟
int minute = localTime.getMinute();
// 3. 获取秒
int second = localTime.getSecond();
// 4. 获取纳秒
int nano = localTime.getNano();
System.out.println("hour = " + hour);
System.out.println("minute = " + minute);
System.out.println("second = " + second);
System.out.println("nano = " + nano);
// 获取指定的日期时间
LocalDateTime localDateTime =
LocalDateTime.of(2022, 8, 6 ,19, 30, 30);
// 增加年月日时分秒, // 2022-08-06T19:30:30
System.out.println("未增加前的时间:" + localDateTime);
// 1. 增加一年
localDateTime = localDateTime.plusYears(1);
// 2. 增加一个月
localDateTime = localDateTime.plusMonths(1);
// 3. 增加一天
localDateTime = localDateTime.plusDays(1);
// 4. 增加一个小时
localDateTime = localDateTime.plusHours(1);
// 5. 增加5分钟
localDateTime = localDateTime.plusMinutes(5);
// 6. 增加10秒
localDateTime = localDateTime.plusSeconds(10);
// 结果:2022-08-06T19:30:30
System.out.println("增加后的时间:" + localDateTime);
// 获取指定的日期时间
LocalDateTime localDateTime =
LocalDateTime.of(2022, 8, 6 ,19, 30, 30);
// 减少年月日时分秒, 2022-08-06T19:30:30
System.out.println("未减少前的时间:" + localDateTime);
// 1. 减少一年
localDateTime = localDateTime.minusYears(1);
// 2. 减少一个月
localDateTime = localDateTime.minusMonths(1);
// 3. 减少一天
localDateTime = localDateTime.minusDays(1);
// 4. 减少一个小时
localDateTime = localDateTime.minusHours(1);
// 5. 减少5分钟
localDateTime = localDateTime.minusMinutes(5);
// 6. 减少10秒
localDateTime = localDateTime.minusSeconds(10);
// 结果: 2021-07-05T18:25:20
System.out.println("减少后的时间:" + localDateTime);
// 获取指定的日期时间
LocalDateTime localDateTime =
LocalDateTime.of(2022, 8, 6 ,19, 30, 30);
// 修改指定的年月日时分秒, // 2022-08-06T19:30:30
System.out.println("未修改前的时间:" + localDateTime);
// 1. 修改年份为2000年
localDateTime = localDateTime.withYear(2000);
// 2. 修改月份为1月
localDateTime = localDateTime.withMonth(1);
// 3. 修改天份为20日
localDateTime = localDateTime.withDayOfMonth(20);
// 4. 修改小时为早上6点
localDateTime = localDateTime.withHour(6);
// 5. 修改分钟为30分钟
localDateTime = localDateTime.withMinute(30);
// 6. 修改秒为30秒
localDateTime = localDateTime.withSecond(30);
// 结果:
System.out.println("修改后的时间:" + localDateTime);
// 创建2个日期
LocalDate date1 = LocalDate.of(2020,5 , 10);
LocalDate date2 = LocalDate.of(2019,5 , 10);
// date1是否在date2之前, // false
boolean before = date1.isBefore(date2);
// date1是否在date2之后, // true
boolean after = date1.isAfter(date2);
// date1 与 date2是否一致, // false
boolean equal = date1.isEqual(date2);
System.out.println("before = " + before);
System.out.println("after = " + after);
System.out.println("equal = " + equal);
// 1. 创建指定的格式化类
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
// 2. 创建JDK中提供好的格式化类
DateTimeFormatter basicIsoDate = DateTimeFormatter.BASIC_ISO_DATE;
// 1. 创建指定的格式化类
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
// 2. 创建一个日期时间类
LocalDateTime localDateTime =
LocalDateTime.of(2022, 8, 6, 19, 30, 30);
// 3. 将日期时间格式化为指定格式的字符串,(1)通过DateTimeFormatter对象格式化
String formatDateTime1 = dateTimeFormatter.format(localDateTime);
System.out.println("formatDateTime1 = " + formatDateTime1);
// 4. 将日期时间格式化为指定格式的字符串,(2)通过LocalDateTime对象格式化
String formatDateTime2 = localDateTime.format(dateTimeFormatter);
System.out.println("formatDateTime2 = " + formatDateTime2);
// 1. 创建指定的格式化类
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// 2. 通过LocalDateTime的parse静态方法
LocalDateTime dateTime1 = LocalDateTime.parse("2020-10-10 20:30:59", dateTimeFormatter);
System.out.println("dateTime1 = " + dateTime1);
// 创建一个时间戳
Instant oldInstant = Instant.now();
System.out.println(oldInstant);
// 为该时间戳增加2天、2小时、2分钟,注意:不支持Period的月和年
Instant newInstance = oldInstant.plus(Duration.ofDays(2).plusHours(2).plusMinutes(2));
System.out.println(newInstance);
// 其余的减少、比较与LocalDateTime等大同小异
// 1. 创建2个日期
LocalDate localDate1 = LocalDate.of(2020, 8, 5);
LocalDate localDate2 = LocalDate.of(2018, 6, 4);
// 2. 创建Period,获取时是:第二个参数 - 第一个参数
Period period = Period.between(localDate2, localDate1);
// 3. 获取相差的年
int years = period.getYears();
System.out.println("years = " + years);
// 4. 获取相差的月
int months = period.getMonths();
System.out.println("months = " + months);
// 5. 获取相差的天数
int days = period.getDays();
System.out.println("days = " + days);
// 1. 创建2个日期
LocalTime localTime1 = LocalTime.of(20,30,30);
LocalTime localTime2 = LocalTime.of(21,31,35);
// 2. 创建duration,获取时是:第二个参数 - 第一个参数
Duration duration = Duration.between(localTime1, localTime2);
// 3. 获取相差的小时
long hours = duration.toHours();
System.out.println("hours = " + hours);
// 4. 获取相差的分钟
long minutes = duration.toMinutes();
System.out.println("minutes = " + minutes);
// 5. 获取相差的秒数
long seconds = duration.getSeconds();
System.out.println("seconds = " + seconds);
// 获取指定的日期时间
LocalDateTime localDateTime1 =
LocalDateTime.of(2022, 8, 6 ,19, 30, 30);
LocalDateTime localDateTime2 =
LocalDateTime.of(2023, 8, 6 ,19, 30, 30);
// 1. 获取相差的年
long years = ChronoUnit.YEARS.between(localDateTime1, localDateTime2);
System.out.println("years = " + years);
// 2. 获取相差的月
long months = ChronoUnit.MONTHS.between(localDateTime1, localDateTime2);
System.out.println("months = " + months);
// 3. 获取相差的日
long days = ChronoUnit.DAYS.between(localDateTime1, localDateTime2);
System.out.println("days = " + days);
// 4. 获取相差的小时
long hours = ChronoUnit.HOURS.between(localDateTime1, localDateTime2);
System.out.println("hours = " + hours);
// 5. 获取相差的分钟
long minutes = ChronoUnit.MINUTES.between(localDateTime1, localDateTime2);
System.out.println("minutes = " + minutes);
// 6. 获取相差的秒
long seconds = ChronoUnit.SECONDS.between(localDateTime1, localDateTime2);
System.out.println("seconds = " + seconds);
LocalDate localDate = LocalDate.of(2000, 10, 20);
System.out.println("矫正前localDate = " + localDate); // 矫正前localDate = 2000-10-20
LocalDate localDate2 = localDate.with(new TemporalAdjuster() {
@Override
public Temporal adjustInto(Temporal temporal) {
LocalDate adjust1 = (LocalDate) temporal;
// 矫正增加2年
adjust1 = adjust1.plusYears(2);
return adjust1;
}
});
System.out.println("矫正后localDate2 = " + localDate2); // 矫正后localDate2 = 2002-10-20
LocalDate localDate = LocalDate.of(2000, 10, 20);
System.out.println("矫正前localDate = " + localDate);// 矫正前localDate = 2000-10-20
// 例如明年的第一天
LocalDate localDate2 = localDate.with(TemporalAdjusters.firstDayOfNextYear());
System.out.println("矫正后localDate2 = " + localDate2); // 矫正后localDate2 = 2001-01-01
// 1. 输出所有时区
ZoneId.getAvailableZoneIds().stream().forEach(System.out::println);
// 2. 创建了标准时间。我们中国比标准时间晚了8个小时
ZonedDateTime now = ZonedDateTime.now(Clock.systemUTC());
System.out.println(now);
// 3. 根据指定的时区创建时间
ZonedDateTime now1 = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println(now1);
// 4. 其他的增加、减少、修改、比较、计算时间差等都跟LocalDateTime一模一样
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我
什么是ruby的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht
这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/
HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候
1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,
Ⅰ软件测试基础一、软件测试基础理论1、软件测试的必要性所有的产品或者服务上线都需要测试2、测试的发展过程3、什么是软件测试找bug,发现缺陷4、测试的定义使用人工或自动的手段来运行或者测试某个系统的过程。目的在于检测它是否满足规定的需求。弄清预期结果和实际结果的差别。5、测试的目的以最小的人力、物力和时间找出软件中潜在的错误和缺陷6、测试的原则28原则:20%的主要功能要重点测(eg:支付宝的支付功能,其他功能都是次要的)80%的错误存在于20%的代码中7、测试标准8、测试的基本要求功能测试性能测试安全性测试兼容性测试易用性测试外观界面测试可靠性测试二、质量模型衡量一个优秀软件的维度①功能性功
目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称
@作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors 1、什么是behaviors 2、behaviors的工作方式 3、创建behavior 4、导入并使用behavior 5、behavior中所有可用的节点 6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors 1、什么是behaviorsbehaviors是小程序中,用于实现