Day28
并行流与串行流
并行流就是把一个内容拆分成多个数据块,并用不同的线程分别处理每个数据块的流。Java8中将并行进行了优化,我们可以很容易的对数据进行并行操作。Stream API可以声明性地通过 parallel() - 并行流 与sequential()-顺序流 之间进行切换。
注意
- 默认为顺序流/串行流
- 并行流一般在大数据搜索里使用到
- JDK1.8之前也有并行流,叫做Fork/Join并行计算框架
Optional
Optional类(java. util. Optional)是一个容器类,代表一个存在或不存在的值,原来用null表示一个值不存在,现在Optional可以更好的表达这个概念。并且可以避免空指针异常
此类的设计就是更好的避免空指针异常
方法 | 描述 |
---|---|
Optional.of(T t) | 创建一个Optional实例 |
Optional.empty() | 创建一 个空的 Optional实例 |
Optional.ofNullable(T t) | 若t不为null,创建Optional实例,否则创建空实例 |
get() | 获取Optional实例里的对象 |
isPresent() | 判断是否包含值 |
orElse(T t) | 如果调用对象包含值, 返回该值,否则返回t |
orElseGet(Supplier s) | 如果调用对象包含值,返回该值,否则返回s获取的值 |
map(Function f) | 如果有值对其处理,并返回处理后的Optional,否则返回optional. empty() |
flatMap(Function mapper) | 与map 类似,要求返回值必须是Optional |
public class Test1 {
@Test
public void test01() {
//创建一个Optional实例,把对象封装到Optional容器里
// Optional<Student> op = Optional.of(
// new Student("aaa", 26, 6666, Course.HTML));
//创建一个空的Optional容器
// Optional<Student> op = Optional.empty();
//创建一个Optional实例,若对象为null->创建空实例,若对象为不为null->创建Optional实例
Optional<Student> op = Optional.ofNullable(
new Student("bbb", 26, 7777, Course.PYTHON));
//判断容器里是否包含对象
if(op.isPresent()){//包含
System.out.println("获取容器里的对象:" + op.get().getName());
}else{//不包含
System.out.println("容器里的对象为null");
}
//如果容器里有对象就返回,否则就返回新对象
Student stu = op.orElse(new Student("ccc", 26, 8888, Course.JAVA));
System.out.println(stu.getName());
//不同情况下可以返回不同对象,orElseGet()比orElse()可变性更强
boolean bool = true;
stu = op.orElseGet(()->{
if(bool){
return new Student("吴彦祖", 26, 8888, Course.JAVA);
}else{
return new Student("麻生希", 26, 8888, Course.JAVA);
}
});
//获取原容器中的某个值并返回新容器中
//map(Function<? super T, ? extends U> mapper)
Optional<String> map = op.map(Student::getName);
System.out.println(map.get());
//与map 类似,要求返回值必须是Optional
//flatMap(Function<? super T, Optional<U>> mapper)
Optional<String> flatMap = op.flatMap((e)->Optional.of(e.getName()));
System.out.println(flatMap.get());
}
}
enum Course{//课程枚举
JAVA,HTML,PYTHON;
}
class Student implements Comparable<Student>{//学生类
private String name;
private int age;
private double salary;
private Course course;
...
}
接口的默认方法与静态方法
从JDK1.8开始,接口中可以有默认方法,既default修饰的方法,此方法可以让接口的实现类所调用,而接口中的静态方法直接用接口名调用即可
public class Test1 {
@Test
public void test01() {
MyClass myClass = new MyClass();
myClass.defaultMethod();
I1.staticMethod();
}
}
interface I1{
default void defaultMethod(){
System.out.println("接口中的默认方法");
}
public static void staticMethod(){
System.out.println("接口中的静态方法");
}
}
class MyClass implements I1{}
接口默认方法的”类优先”原则:
如果一个接口中定义了一个默认方法,而接口实现类的父类定义了一个同名的方法时,选择父类中的方法
接口冲突:
如果一个父接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认方法),那么必须覆盖该方法来解决冲突
接口冲突:
一个类实现多个接口,多个接口都有相同名字的默认方法时,实现类必须重写
public class Test1 {
@Test
public void test01() {
MyClass myClass = new MyClass();
myClass.method();
}
}
interface I1{
default void method(){
System.out.println("I1接口中的默认方法");
}
}
class Father {
public void method(){
System.out.println("Father类中的默认方法");
}
}
class MyClass extends Father implements I1 {}
public class Test1 {
@Test
public void test01() {
MyClass myClass = new MyClass();
myClass.method();
}
}
interface I1{
default void method(){
System.out.println("I1接口中的默认方法");
}
}
interface I2{
default void method(){
System.out.println("I2接口中的默认方法");
}
}
class MyClass implements I1,I2 {
@Override
public void method() {
//I1.super.method();
I2.super.method();
}
}
日期组件
组件简介
包路径 | 类名 | 描述 |
---|---|---|
java.time | 针对日期和时间操作的包 | |
LocalDate | 用于表示日期的类 | |
LocalTime | 用于表示时间的类 | |
LocalDateTime | 用于表示日期时间的类 | |
Instant | 时间戳类(1970.1.1 0:0:0 到现在的毫秒数) | |
Period | 两个日期间隔类 | |
Duration | 两个时间间隔类 | |
java.time.chrono | 针对日期时间特殊格式操作的包 | |
JapaneseChronology | 日本帝国历法系统类 | |
ThaiBuddhistChronology | 泰国佛教日历系统类 | |
java.time.format | 针对时间日期时间格式化操作的包 | |
DateTimeFormatter | 格式化日期时间类 | |
java.time.temporal | 针对时间矫正操作的包 | |
java.time.zone | 针对时区操作的包 |
日期时间格式化类-DateTimeFormatter
public class Test1 { @Test public void test01() { //格式化日期时间类 LocalDateTime ldt1 = LocalDateTime.now(); //获取本地标准的日期时间格式化对象 DateTimeFormatter dtf1 = DateTimeFormatter.ISO_LOCAL_DATE_TIME; String strDateTime1 = ldt1.format(dtf1);//格式化时间日期 System.out.println(strDateTime1); //自定义日期时间格式化对象 DateTimeFormatter dtf2 = DateTimeFormatter. ofPattern("yyyy年MM月dd日 HH:mm:ss"); String strDateTime2 = ldt1.format(dtf2);//格式化时间日期 System.out.println(strDateTime2); //将指定格式的字符串解析成LocalDateTime对象 LocalDateTime parse = LocalDateTime.parse("2020年03月12日 11:04:14", dtf2); System.out.println(parse); } }
知识点:多线程下使用日期时间类的问题
public class Test01 { /** * 知识点:多线程下使用日期时间类的问题 */ public static void main(String[] args) throws InterruptedException, ExecutionException { SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); Callable<Date> callable = new Callable<Date>() { @Override public Date call() throws Exception { Date date = sdf.parse("20240529"); return date; } }; ArrayList<Future<Date>> list = new ArrayList<>(); ExecutorService pool = Executors.newFixedThreadPool(10); for (int i = 1; i <=10; i++) { Future<Date> future = pool.submit(callable); list.add(future); } for (Future<Date> future : list) { System.out.println(future.get()); } pool.shutdown(); } }//会报错,因为SimpleDateFormat线程不安全
以下是正确的代码:
public class Test02 { /** * 知识点:多线程下使用日期时间类的问题 */ public static void main(String[] args) throws InterruptedException, ExecutionException { DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd"); Callable<LocalDate> callable = new Callable<LocalDate>() { @Override public LocalDate call() throws Exception { LocalDate localDate = LocalDate.parse("20240529", dtf); return localDate; } }; ArrayList<Future<LocalDate>> list = new ArrayList<>(); ExecutorService pool = Executors.newFixedThreadPool(10); for (int i = 1; i <=10; i++) { Future<LocalDate> future = pool.submit(callable); list.add(future); } for (Future<LocalDate> future : list) { System.out.println(future.get()); } pool.shutdown(); } }
重复注解
jdk1.8开始可以重复注解
ps:一个类可有多个同样的注解
import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.TYPE_PARAMETER; import java.lang.annotation.Annotation; import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Method; import org.junit.Test; //重复注解 @Author(name="何老师") @Author(name="苍老师") public class Test1<@Author(name="xxx") T> { @Test public void test01() throws Exception{ //需求1:获取Test1的多个作者注解 Class<?> ct = Test1.class; Author[] as = ct.getAnnotationsByType(Author.class); for (Author a : as) { System.out.println(a.name()); } //需求2:获取method方法中参数里的注解 Method m = ct.getMethod("method", String.class); Annotation[][] parameterAnnotations = m.getParameterAnnotations(); //获取参数中注解列表(有可能一个参数多个注解) for (Annotation[] annotations : parameterAnnotations) { for (Annotation an : annotations) {//获取具体注解 System.out.println(an); } } } public static void method(@Author(name="波老师") String str){} } //作者注解的容器 @Target(TYPE) @Retention(RetentionPolicy.RUNTIME) @interface Authors{ Author[] value(); } //作者注解 @Repeatable(Authors.class) //TYPE_PARAMETER-类型注解:作用泛型 @Target({TYPE, PARAMETER,TYPE_PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @interface Author{ String name(); }