目录
· 初步理解
· 应用模式
· 优先级问题
· Optional
· 基本用法
· CompletableFuture与Stream API
· 旧API
· 创建
· 操作
· 格式化与解析
· 时区
默认方法和静态方法
初步理解
1. 面临问题:Java 8以前,当已设计的接口被其他框架、库使用后,如果向接口添加新方法,将导致这些框架和库无法编译。
2. 解决方法:Java 8可在接口中使用静态方法和默认方法。
应用模式
1. 合并接口与辅助工具类:比如接口java.util.Collection与其辅助工具类java.util.Collections,接口支持静态方法后,可将辅助工具类的方法加入到接口。
2. 可选方法:比如JDK中的java.util.Iterator,接口提供一个默认的remove()实现,这样实体类就无需在自己的实现中显式地提供一个空方法。
1 interface Iterator<T> { 2 3 boolean hasNext(); 4 5 T next(); 6 7 default void remove() { 8 throw new UnsupportedOperationException(); 9 } 10 11 }
3. 行为多继承
a) Rotatable.java
1 public interface Rotatable { 2 3 void setRotationAngle(int angleInDegrees); 4 5 int getRotationAngle(); 6 7 default void rotateBy(int angleInDegrees) { 8 setRotationAngle((getRotationAngle() + angleInDegrees) % 360); 9 } 10 11 }
b) Moveable.java
1 public interface Moveable { 2 3 int getX(); 4 5 int getY(); 6 7 void setX(int x); 8 9 void setY(int y); 10 11 default void moveHorizontally(int distance) { 12 setX(getX() + distance); 13 } 14 15 default void moveVertically(int distance) { 16 setY(getY() + distance); 17 } 18 19 }
c) Resizable.java
1 public interface Resizable { 2 3 int getWidth(); 4 5 int getHeight(); 6 7 void setWidth(int width); 8 9 void setHeight(int height); 10 11 void setAbsoluteSize(int width, int height); 12 13 default void setRelativeSize(int wFactor, int hFactor) { 14 setAbsoluteSize(getWidth() / wFactor, getHeight() / hFactor); 15 } 16 17 }
d) Monster.java
1 public class Monster implements Rotatable, Moveable, Resizable { 2 3 @Override 4 public int getX() { 5 return 0; 6 } 7 8 @Override 9 public int getY() { 10 return 0; 11 } 12 13 @Override 14 public void setX(int x) { 15 } 16 17 @Override 18 public void setY(int y) { 19 20 } 21 22 @Override 23 public int getWidth() { 24 return 0; 25 } 26 27 @Override 28 public int getHeight() { 29 return 0; 30 } 31 32 @Override 33 public void setWidth(int width) { 34 } 35 36 @Override 37 public void setHeight(int height) { 38 } 39 40 @Override 41 public void setAbsoluteSize(int width, int height) { 42 } 43 44 @Override 45 public void setRotationAngle(int angleInDegrees) { 46 } 47 48 @Override 49 public int getRotationAngle() { 50 return 0; 51 } 52 53 }
e) Sun.java
1 public class Sun implements Moveable, Rotatable { 2 3 @Override 4 public int getX() { 5 return 0; 6 } 7 8 @Override 9 public int getY() { 10 return 0; 11 } 12 13 @Override 14 public void setX(int x) { 15 } 16 17 @Override 18 public void setY(int y) { 19 } 20 21 @Override 22 public void setRotationAngle(int angleInDegrees) { 23 } 24 25 @Override 26 public int getRotationAngle() { 27 return 0; 28 } 29 30 }
优先级问题
1. 方法执行优先级规则:
a) 距离当前类越近的方法优先级越高;
b) 显示方法近于隐式方法;
c) 距离相等时,非默认方法优先于默认方法。
2. 举例
a) hello()方法优先级:B > A。
i. A.java
1 public interface A { 2 3 default void hello() { 4 System.out.println("Hello from A"); 5 } 6 7 }
ii. B.java
1 public interface B extends A { 2 3 default void hello() { 4 System.out.println("Hello from B"); 5 } 6 7 }
iii. C.java
1 public class C implements B, A { 2 3 public static void main(String[] args) { 4 new C().hello(); // Hello from B 5 } 6 7 }
b) hello()方法优先级:B > A。
i. A.java
1 public interface A { 2 3 default void hello() { 4 System.out.println("Hello from A"); 5 } 6 7 }
ii. B.java
1 public interface B extends A { 2 3 default void hello() { 4 System.out.println("Hello from B"); 5 } 6 7 }
iii. D.java
1 public class D implements A{ 2 }
iv. C.java
1 public class C extends D implements B, A { 2 3 public static void main(String[] args) { 4 new C().hello(); // Hello from B 5 } 6 7 }
c) hello()方法优先级:D > B > A。
i. A.java
1 public interface A { 2 3 default void hello() { 4 System.out.println("Hello from A"); 5 } 6 7 }
ii. B.java
1 public interface B extends A { 2 3 default void hello() { 4 System.out.println("Hello from B"); 5 } 6 7 }
iii. D.java
1 public class D implements A { 2 3 @Override 4 public void hello() { 5 System.out.println("Hello from D"); 6 } 7 8 }
iv. C.java
1 public class C extends D implements B, A { 2 3 public static void main(String[] args) { 4 new C().hello(); // Hello from D 5 } 6 7 }
d) hello()方法优先级:C > B = A,由于A、B优先级相等,有冲突,所以必须在C中Override hello()方法,否则将报错class C inherits unrelated defaults for hello() from types B and A。
i. A.java
1 public interface A { 2 3 default void hello() { 4 System.out.println("Hello from A"); 5 } 6 7 }
ii. B.java
1 public interface B { 2 3 default void hello() { 4 System.out.println("Hello from B"); 5 } 6 7 }
iii. C.java
1 public class C implements B, A { 2 3 @Override 4 public void hello() { 5 B.super.hello(); 6 } 7 8 public static void main(String[] args) { 9 new C().hello(); // Hello from B 10 } 11 12 }
Optional
1. Optional目的:解决null带来的以下问题。
a) 错误:NullPointerException。
b) 代码膨胀:代码充斥着深度嵌套的null检查,可读性变差。
c) 毫无意义:null自身没有任何语义,它代表在静态类型语言中以一种错误的方式对缺失变量值的建模。
d) 破坏了Java的哲学:Java一直试图避免让程序员意识到指针的存在,唯一的例外是null指针。
e) 类型缺陷:null并不属于任何类型,它可以被赋值给任意引用类型的变量。这导致当这个变量被传递到系统中的另一个部分后,将无法获知null变量最初的赋值到底是什么类型。
2. java.util.Optional类的方法
方法 |
描述 |
empty |
返回空Optional实例 |
filter |
如果值存在并且满足提供的Predicate,则返回包含该值的Optional对象;否则返回空Optional对象 |
flatMap |
如果值存在,就对该值执行提供的mapping函数,返回Optional类型的值,否则返回一个空Optional对象 |
get |
如果值存在,将该值用Optional封装返回,否则抛出NoSuchElementException异常 |
ifPresent |
如果值存在,则执行使用该值的方法调用,否则什么也不做 |
isPresent |
如果值存在,则返回true,否则返回false |
map |
如果值存在,则对该值执行提供的mapping函数 |
of |
将指定值用Optional封装后返回,如果该值为null,则抛出NullPointerException异常 |
ofNullable |
将指定值用Optional封装后返回,如果该值为null,则返回空Optional对象 |
orElse |
如果有值,则将其返回,否则返回一个默认值 |
orElseGet |
如果有值,则将其返回,否则返回由指定Supplier接口生成的值 |
orElseThrow |
如果有值,则将其返回,否则抛出指定的Supplier接口生成的异常 |
3.举例
a) 使用Optional前
i. Person.java
1 public class Person { 2 3 private Car car; 4 5 public Car getCar() { 6 return car; 7 } 8 9 }
ii. Car.java
1 public class Car { 2 3 private Insurance insurance; 4 5 public Insurance getInsurance() { 6 return insurance; 7 } 8 9 }
iii. Insurance.java
1 public class Insurance { 2 3 private String name; 4 5 public String getName() { 6 return name; 7 } 8 9 }
iv. Test.java
1 public class Test { 2 3 public static String getCarInsuranceName(Person person) { 4 if (person != null) { 5 Car car = person.getCar(); 6 if (car != null) { 7 Insurance insurance = car.getInsurance(); 8 if (insurance != null) { 9 return insurance.getName(); 10 } 11 } 12 } 13 return "Unknown"; 14 } 15 16 }
b) 使用Optional后
i. Person.java
1 import java.util.Optional; 2 3 public class Person { 4 5 // 可能为null 6 private Car car; 7 8 public Optional<Car> getCar() { 9 // 使用Optional封装car,允许car为null 10 return Optional.ofNullable(car); 11 } 12 13 }
ii. Car.java
1 import java.util.Optional; 2 3 public class Car { 4 5 // 可能为null 6 private Insurance insurance; 7 8 public Optional<Insurance> getInsurance() { 9 return Optional.ofNullable(insurance); 10 } 11 12 }
iii. Insurance.java
1 public class Insurance { 2 3 // 不可能为null 4 private String name; 5 6 // 不可能为null,所以不使用Optional 7 public String getName() { 8 return name; 9 } 10 11 }
iv. Test.java
1 import java.util.Optional; 2 3 public class Test { 4 5 public static String getCarInsuranceName(Person person) { 6 Optional<Person> optPerson = Optional.ofNullable(person); 7 // 由于Person::getCar返回类型是Optional<Car>, 8 // 所以optPerson.map(Person::getCar)返回类型是Optional<Optional<Car>>, 9 // 因此导致map(Car::getInsurance)报错 10 // Optional<String> name = optPerson.map(Person::getCar) 11 // .map(Car::getInsurance) 12 // .map(Insurance::getName); 13 // 使用flatMap扁平化,从而避免上述报错 14 return optPerson.flatMap(Person::getCar) 15 .flatMap(Car::getInsurance) 16 .map(Insurance::getName) 17 .orElse("Unknown"); // 如果Optional结果值为空,则使用默认值 18 } 19 20 }
c) 使用filter()方法判断Predicate
1 // 不使用Optional 2 Insurance insurance = null; 3 if(insurance != null && "CambridgeInsurance".equals(insurance.getName())){ 4 System.out.println("ok"); 5 } 6 // 使用Optional 7 Optional<Insurance> optInsurance = Optional.ofNullable(null); 8 optInsurance.filter(ins -> "CambridgeInsurance".equals(ins.getName())) 9 .ifPresent(ins -> System.out.println("ok"));
CompletableFuture
基本用法
1. java.util.concurrent.Future接口
a) 起始:Java 5。
b) 使用方法:通常需要将耗时操作封装在一个Callable对象中,再将它提交给ExecutorService执行,最后通过Future获取执行结果。
2. java.util.concurrent.CompletableFuture类
a) 起始:Java 8。
b) 优点:比Future更加直观,功能更强大。
3. 举例
a) Future
i. Shop.java
1 import java.util.concurrent.*; 2 3 public class Shop { 4 5 public double getPrice(String product) { 6 return calculatePrice(product); 7 } 8 9 public Future<Double> getPriceAsync(String product) { 10 ExecutorService executor = Executors.newCachedThreadPool(); 11 Future<Double> future = executor.submit(new Callable<Double>() { 12 public Double call() { 13 return getPrice(product); 14 } 15 }); 16 return future; 17 } 18 19 private double calculatePrice(String product) { 20 delay(); 21 return Math.random() * 1000; 22 } 23 24 private static void delay() { 25 try { 26 Thread.sleep(1000L); 27 } catch (InterruptedException e) { 28 throw new RuntimeException(e); 29 } 30 } 31 32 }
ii. Test.java
1 import java.util.concurrent.*; 2 3 public class Test { 4 5 public static void main(String[] args) { 6 try { 7 Future<Double> future = new Shop().getPriceAsync("Candy"); 8 Double price = future.get(); 9 System.out.println(price); 10 } catch (InterruptedException e) { 11 e.printStackTrace(); 12 } catch (ExecutionException e) { 13 e.printStackTrace(); 14 } 15 } 16 17 }
b) CompletableFuture方法一
1 import java.util.concurrent.*; 2 3 public class Shop { 4 5 public double getPrice(String product) { 6 return calculatePrice(product); 7 } 8 9 public Future<Double> getPriceAsync(String product) { 10 CompletableFuture<Double> future = new CompletableFuture<>(); 11 new Thread(() -> { 12 try { 13 double price = getPrice(product); 14 future.complete(price); // 如果价格计算正常结束,完成Future操作并设置商品价格 15 } catch (Exception ex) { 16 future.completeExceptionally(ex); // 否则就抛出导致失败的异常,完成这次Future操作 17 } 18 }).start(); 19 return future; 20 } 21 22 private double calculatePrice(String product) { 23 delay(); 24 return Math.random() * 1000; 25 } 26 27 private static void delay() { 28 try { 29 Thread.sleep(1000L); 30 } catch (InterruptedException e) { 31 throw new RuntimeException(e); 32 } 33 } 34 35 }
c) CompletableFuture方法二
1 import java.util.concurrent.*; 2 3 public class Shop { 4 5 public double getPrice(String product) { 6 return calculatePrice(product); 7 } 8 9 public Future<Double> getPriceAsync(String product) { 10 return CompletableFuture.supplyAsync(() -> calculatePrice(product)); 11 } 12 13 private double calculatePrice(String product) { 14 delay(); 15 return Math.random() * 1000; 16 } 17 18 private static void delay() { 19 try { 20 Thread.sleep(1000L); 21 } catch (InterruptedException e) { 22 throw new RuntimeException(e); 23 } 24 } 25 26 }
CompletableFuture与Stream API
1. 并行流与顺序流+CompletableFuture都可以实现流的并行处理,如何选取?
a) 灵活
i. 并行流:线程数由ForkJoinPool的全局属性决定。
ii. 顺序流+CompletableFuture:自由创建线程池,灵活控制线程数。
b) 场景
i. 并行流:更适合计算密集型并且没有I/O的操作,因为实现简单,同时效率更高(如果所有的线程都是计算密集型,则没有必要创建比CPU核数更多的线程)。
ii. 顺序流+CompletableFuture:更适合并行工作单元涉及I/O等待(包括网络连接等待)的操作,该场景不使用并行流的另一个原因是处理流的流水线中如果发生I/O等待,流的延迟特性会让我们很难判断到底什么时候触发了等待。该场景线程数用以下公式计算(出自《Java并发编程实战》):
NCPU为CPU核数,可通过Runtime.getRuntime().availableProcessors()获取。
UCPU为期望的CPU利用率(应介于0和1之间)。
W/C是等待时间与计算时间的比率。
2. 举例
a) Shop.java
1 public class Shop { 2 3 private String name; 4 5 public Shop(String name) { 6 this.name = name; 7 } 8 9 public String getName() { 10 return name; 11 } 12 13 public double getPrice(String product) { 14 return calculatePrice(product); 15 } 16 17 private double calculatePrice(String product) { 18 delay(); 19 return Math.random() * 1000; 20 } 21 22 private static void delay() { 23 try { 24 Thread.sleep(1000L); 25 } catch (InterruptedException e) { 26 throw new RuntimeException(e); 27 } 28 } 29 30 }
b) Test.java
1 import java.util.*; 2 import java.util.concurrent.*; 3 4 import static java.util.stream.Collectors.toList; 5 6 public class Test { 7 8 // 顺序流 9 public static List<String> findPrices1(List<Shop> shops, String product) { 10 return shops.stream() 11 .map(shop -> String.format("%s price is %.2f", shop.getName(), shop.getPrice(product))) 12 .collect(toList()); 13 } 14 15 // 并行流 16 public static List<String> findPrices2(List<Shop> shops, String product) { 17 return shops.parallelStream() 18 .map(shop -> String.format("%s price is %.2f", shop.getName(), shop.getPrice(product))) 19 .collect(toList()); 20 } 21 22 // 顺序流+CompletableFuture 23 public static List<String> findPrices3(List<Shop> shops, String product) { 24 // 创建一个线程池,线程池中线程的数目为100和商店数目二者中较小的一个值 25 Executor executor = Executors.newFixedThreadPool(Math.min(shops.size(), 100), 26 new ThreadFactory() { 27 public Thread newThread(Runnable r) { 28 Thread t = new Thread(r); 29 t.setDaemon(true); // 使用守护线程——这种方式不会阻止程序的关停 30 return t; 31 } 32 }); 33 List<CompletableFuture<String>> priceFutures = shops.stream() 34 .map(shop -> CompletableFuture.supplyAsync(() -> String.format("%s price is %.2f", shop.getName(), shop.getPrice(product)), executor)) 35 .collect(toList()); 36 return priceFutures.stream() 37 .map(CompletableFuture::join) // 等待所有异步操作结束 38 .collect(toList()); 39 } 40 41 public static void printPrices(List<String> prices) { 42 prices.stream().forEach(System.out::println); 43 } 44 45 public static void main(String[] args) { 46 List<Shop> shops = Arrays.asList(new Shop("BestPrice"), 47 new Shop("LetsSaveBig"), 48 new Shop("MyFavoriteShop"), 49 new Shop("BuyItAll")); 50 String product = "Candy"; 51 List<String> prices1 = findPrices1(shops, product); 52 printPrices(prices1); 53 List<String> prices2 = findPrices2(shops, product); 54 printPrices(prices2); 55 List<String> prices3 = findPrices3(shops, product); 56 printPrices(prices3); 57 } 58 59 }
新日期和时间API
旧API
1. java.util.Date
a) 起始:Java 1.0。
b) 缺点:只能以毫秒精度表示时间;易用性差,比如年份从1900开始,月份从0开始。
1 // 2014年3月18日 2 System.out.println(new Date(114, 2, 18));
2.java.util.Calendar
a) 起始:Java 1.1。
b) 缺点:易用性差,比如月份从0开始;Date和Calendar如何选择问题;格式化类DateFormat只能用于Date。
创建
1. java.time.LocalDate
a) 只存储年、月、日,不存储时区。
b) 不可变,线程安全。
2. java.time.LocalTime
a) 只存储时、分、秒,不存储时区。
b) 不可变,线程安全。
3. java.time.LocalDateTime
a) 只存储年、月、日、时、分、秒,不存储时区。
b) 不可变,线程安全。
c) LocalDate和LocalTime的合体。
4. java.time.Instant
a) Unix时间戳秒数,即与UTC时区1970-01-01 00:00:00的秒数和纳秒差值。
b) 内部存储秒数和纳秒(1 ns = 10^-9 s)两个字段。
c) 面向机器设计的类,方便机器处理。
5. java.time.temporal.ChronoField
a) 实现了java.time.temporal.TemporalFieldl接口的枚举,提供了访问java.time.temporal.Temporal接口实现类的标准字段。
b) LocalDate、LocalTime、LocalDateTime和Instant实现了Temporal接口。
c) 注意:由于Instant是面向机器的,通过ChronoField获取Instant字段时,只支持秒、毫秒(1,000毫秒=1秒)、微秒(1,000,000微秒=1秒)和纳秒(1,000,000,000纳秒=1秒)。
6. java.time.Duration
a) 表示一个时间段的持续时长。
b) 内部存储持续时长的秒和纳秒。
7. java.time.Period
a) 表示一个时间段的持续时长。
b) 内部存储持续时长的年、月、日。
8. Duration和Period的通用方法
方法 |
静态方法 |
描述 |
between |
Y |
创建两个时间点之间的间隔时长 |
from |
Y |
由一个临时时间点创建间隔时长 |
of |
Y |
由组成部分创建时长的实例 |
parse |
Y |
由字符串创建时长的实例 |
addTo |
N |
创建该时长的副本,并将其叠加到某个指定的Temporal对象 |
get |
N |
读取该时长的状态 |
isNegative |
N |
检查该时长是否为负值,不包含零 |
isZero |
N |
检查该时长的时长是否为零 |
minus |
N |
通过减去一定的时间创建该时长的副本 |
multipliedBy |
N |
将时长的值乘以某个标量创建该时长的副本 |
negated |
N |
以忽略某个时长的方式创建该时长的副本 |
plus |
N |
以增加某个指定时长的方式创建该时长的副本 |
subtractFrom |
N |
从指定的Temporal对象中减去该时长 |
9. 举例
a) java.time.LocalDate
1 // 创建 2 LocalDate today = LocalDate.now(); 3 LocalDate d = LocalDate.parse("2014-03-18"); 4 LocalDate date = LocalDate.of(2014, 3, 18); // 2014-03-18 5 // 直接获取字段 6 int year = date.getYear(); // 2014 7 Month month = date.getMonth(); // MARCH 8 int day = date.getDayOfMonth(); // 18 9 DayOfWeek dow = date.getDayOfWeek(); // TUESDAY 10 int len = date.lengthOfMonth(); // 31 (3月总天数) 11 boolean leap = date.isLeapYear(); // false 12 // 通过ChronoField获取字段 13 int year = date.get(ChronoField.YEAR); // 2014 14 int month = date.get(ChronoField.MONTH_OF_YEAR); // 3 15 int day = date.get(ChronoField.DAY_OF_MONTH); // 18
b) java.time.LocalTime
1 // 创建 2 LocalTime t = LocalTime.parse("13:45:20"); 3 LocalTime time = LocalTime.of(13, 45, 20); // 13:45:20 4 // 直接获取字段 5 int hour = time.getHour(); // 13 6 int minute = time.getMinute(); // 45 7 int second = time.getSecond(); // 20
c) java.time.LocalDateTime
1 // 创建2014-03-18T13:45:20的4种方法 2 LocalDateTime dt1 = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45, 20); 3 LocalDateTime dt2 = LocalDateTime.of(date, time); 4 LocalDateTime dt3 = date.atTime(13, 45, 20); 5 LocalDateTime dt4 = date.atTime(time); 6 // 提取 7 LocalDate date1 = dt1.toLocalDate(); // 2014-03-18 8 LocalTime time1 = dt1.toLocalTime(); // 13:45:20
d) java.time.Instant
1 // 创建1970-01-01T00:00:03Z的4种方法 2 Object o1 = Instant.ofEpochSecond(3); 3 Object o2 = Instant.ofEpochSecond(3, 0); 4 Object o3 = Instant.ofEpochSecond(2, 1_000_000_000); // 2秒之后再加上100万纳秒(1秒) 5 Object o4 = Instant.ofEpochSecond(4, -1_000_000_000); // 4秒之前的100万纳秒(1秒) 6 // Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: DayOfMonth 7 int day = Instant.now().get(ChronoField.DAY_OF_MONTH);
e) java.time.Duration
1 // 创建3秒持续时长的5种方法 2 Duration d1 = Duration.between(LocalTime.parse("00:00:00"), LocalTime.parse("00:00:03")); 3 Duration d2 = Duration.between(LocalDateTime.parse("1970-01-01T00:00:00"), LocalDateTime.parse("1970-01-01T00:00:03")); 4 Duration d3 = Duration.between(Instant.ofEpochSecond(0), Instant.ofEpochSecond(3)); 5 Duration d4 = Duration.ofSeconds(3); 6 Duration d5 = Duration.of(3, ChronoUnit.SECONDS);
f) java.time.Period
1 // 创建10天持续时长的3种方法 2 Period p1 = Period.between(LocalDate.of(2014, 3, 8), LocalDate.of(2014, 3, 18)); 3 Period p2 = Period.ofDays(10); 4 Period p3 = Period.of(0, 0, 10);
操作
1. 操作相关方法
a) with*()方法:创建某字段为新值的新Temporal对象。
b) plus*()方法:创建加上某个时长的新Temporal对象。
c) minus*()方法:创建减去某个时长的新Temporal对象。
d) java.time.temporal.TemporalAdjuster.*方法:高级日期时间操作方法
方法 |
描述 |
dayOfWeekInMonth |
创建一个新日期,它的值为同一个月中每一周的第几天 |
firstDayOfMonth |
创建一个新日期,它的值为当月的第一天 |
firstDayOfNextMonth |
创建一个新日期,它的值为下月的第一天 |
firstDayOfNextYear |
创建一个新日期,它的值为明年的第一天 |
firstDayOfYear |
创建一个新日期,它的值为当年的第一天 |
firstInMonth |
创建一个新日期,它的值为同一个月中,第一个符合星期几要求的值 |
lastDayOfMonth |
创建一个新日期,它的值为下月的最后一天 |
lastDayOfNextMonth |
创建一个新日期,它的值为下月的最后一天 |
lastDayOfNextYear |
创建一个新日期,它的值为明年的最后一天 |
lastDayOfYear |
创建一个新日期,它的值为今年的最后一天 |
lastInMonth |
创建一个新日期,它的值为同一个月中,最后一个符合星期几要求的值 |
next previous |
创建一个新日期,并将其值设置为日期调整后或调整前,第一个符合指定星期几要求的日期 |
nextOrSame previousOrSame |
创建一个新日期,并将其值设置为日期调整后或调整前,第一个符合指定星期几要求的日期,如果该日期已经符合要求,直接返回该对象 |
2. 举例
a) with*()方法
1 LocalDate date1 = LocalDate.of(2014, 3, 18); // 2014-03-18 2 LocalDate date2 = date1.withYear(2011); // 2011-03-18 3 LocalDate date3 = date2.withDayOfMonth(25); // 2011-03-25 4 LocalDate date4 = date3.with(ChronoField.MONTH_OF_YEAR, 9); // 2011-09-25
b) plus*()方法和minus*()方法
1 LocalDate date1 = LocalDate.of(2014, 3, 18); // 2014-03-18 2 LocalDate date2 = date1.plusWeeks(1); // 2014-03-25 3 LocalDate date3 = date2.minusYears(3); // 2011-03-25 4 LocalDate date4 = date3.plus(6, ChronoUnit.MONTHS); // 2011-09-25
c) TemporalAdjuster.*方法
1 import static java.time.temporal.TemporalAdjusters.*; 2 LocalDate date1 = LocalDate.of(2014, 3, 18); // 2014-03-18 3 LocalDate date2 = date1.with(nextOrSame(DayOfWeek.SUNDAY)); // 2014-03-23 4 LocalDate date3 = date2.with(lastDayOfMonth()); // 2014-03-31
d) 自定义TemporalAdjuster:计算下一个工作日(仅跳过周六日)
1 TemporalAdjuster nextWorkingDay = TemporalAdjusters.ofDateAdjuster( 2 temporal -> { 3 DayOfWeek dow = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK)); 4 int dayToAdd = 1; 5 if (dow == DayOfWeek.FRIDAY) dayToAdd = 3; 6 if (dow == DayOfWeek.SATURDAY) dayToAdd = 2; 7 return temporal.plus(dayToAdd, ChronoUnit.DAYS); 8 }); 9 date = date.with(nextWorkingDay); // 2014-03-19
格式化与解析
1. java.time.format.DateTimeFormatter
a) 用于格式化和解析。
b) 线程安全。
2. 举例
a) 使用内置格式格式化与解析
1 // 格式化 2 LocalDate date = LocalDate.of(2014, 3, 18); 3 String s1 = date.format(DateTimeFormatter.BASIC_ISO_DATE); // 20140318 4 String s2 = date.format(DateTimeFormatter.ISO_LOCAL_DATE); // 2014-03-18 5 // 解析 6 LocalDate date1 = LocalDate.parse("20140318", DateTimeFormatter.BASIC_ISO_DATE); 7 LocalDate date2 = LocalDate.parse("2014-03-18", DateTimeFormatter.ISO_LOCAL_DATE);
b) 使用模式自定义格式式化与解析
1 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日"); 2 // 格式化 3 LocalDate date1 = LocalDate.of(2014, 3, 18); 4 String formattedDate = date1.format(formatter); 5 // 解析 6 LocalDate date2 = LocalDate.parse(formattedDate, formatter);
c) 更复杂方式自定义格式式化与解析
1 DateTimeFormatter formatter = new DateTimeFormatterBuilder() 2 .appendValue(ChronoField.YEAR, 4, 10, SignStyle.EXCEEDS_PAD) 3 .appendLiteral("年") 4 .appendValue(ChronoField.MONTH_OF_YEAR, 2) 5 .appendLiteral("月") 6 .appendValue(ChronoField.DAY_OF_MONTH, 2) 7 .appendLiteral("日") 8 .parseCaseInsensitive() 9 .toFormatter(); 10 // 格式化 11 LocalDate date1 = LocalDate.of(2014, 3, 18); 12 String formattedDate = date1.format(formatter); 13 // 解析 14 LocalDate date2 = LocalDate.parse(formattedDate, formatter);
时区
1. java.time.ZoneId类:替换java.util.TimeZone的新时区类。
2. 举例
a) 获取时区
1 // 北京时间 2 ZoneId beijingZone = ZoneId.of("Asia/Shanghai"); 3 // 默认时区 4 ZoneId zoneId = TimeZone.getDefault().toZoneId();
b) 设置时区
1 LocalDate date = LocalDate.of(2014, Month.MARCH, 18); 2 ZonedDateTime zdt1 = date.atStartOfDay(beijingZone); 3 LocalDateTime dateTime = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45); 4 ZonedDateTime zdt2 = dateTime.atZone(beijingZone); 5 Instant instant = Instant.now(); 6 ZonedDateTime zdt3 = instant.atZone(beijingZone);
作者:netoxi
出处:http://www.cnblogs.com/netoxi
本文版权归作者和博客园共有,欢迎转载,未经同意须保留此段声明,且在文章页面明显位置给出原文连接。欢迎指正与交流。