java8 新特性

java8新特性总结

  • 行为参数化
  • lambda表达式
  • Stream Api

1. 行为参数化

  • 定义:行为参数化,就是一个方法接受多个不同的行为作为参数,并在内部使用它们,完成不同行为的能力。

  • 行为参数化可让代码更好地适应不断变化的要求,减轻未来的工作量。传递代码,就是将新行为作为参数传递给方法。

  • 方法引用:在Java 8里写下 类::方法名的时候,你就创建了一个方法引用,你同样可以传递它。

package org.study.firstbase;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * Hello world!
 */
public class AppFilter {

    public static void main(String[] args) {
        testPredicate();
    }

    public static void testPredicate() {
        List<Apple> apples = new ArrayList<Apple>();
        apples.add(new Apple("green", 140));
        apples.add(new Apple("green", 160));
        apples.add(new Apple("red", 140));
        apples.add(new Apple("red", 160));

        List<Apple> result = filterApples(apples, Apple::isGreenApple);
        for (Apple apple : result) {
            System.out.println(apple);
        }

        List<Apple> result2 = filterApples(apples, Apple::isHeavyApple);
        for (Apple apple : result2) {
            System.out.println(apple);
        }
    }

    static List<Apple> filterApples(List<Apple> inventory, Predicate<Apple> p) {
        List<Apple> result = new ArrayList<Apple>();
        for (Apple apple : inventory) {
            if (p.test(apple)) {
                result.add(apple);
            }
        }
        return result;
    }
}

class Apple {
    private String color;
    private int weight;

    public Apple(String color, int weight) {
        this.color = color;
        this.weight = weight;
    }

    public static boolean isGreenApple(Apple apple) {
        return "green".equals(apple.getColor());
    }

    public static boolean isHeavyApple(Apple apple) {
        return apple.getWeight() > 150;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    @Override
    public String toString() {
        return "Apple{" +
                "color='" + color + '\'' +
                ", weight=" + weight +
                '}';
    }
}

2. lambda表达式

你可以在函数式接口上使用Lambda表达式

2.1 函数式接口

在这里插入图片描述

2.2 函数描述符

函数式接口的抽象方法的签名基本上就是Lambda表达式的签名。我们将这种抽象方法叫作函数描述符

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3. Stream API

  • 流是“从支持数据处理操作的源生成的一系列元素”。
  • 流操作有两类:中间操作终端操作
  • 谓词:一个返回 boolean的函数
  • 总结
    • Streams API可以表达复杂的数据处理查询。常用的流操作总结在表5-1中。
    • 你可以使用filter、distinct、skip和limit对流做筛选和切片。
    • 你可以使用map和flatMap提取或转换流中的元素。 你可以使用findFirst和findAny方法查找流中的元素。你可以用allMatch、noneMatch和anyMatch方法让流匹配给定的谓词。
    • 这些方法都利用了短路:找到结果就立即停止计算;没有必要处理整个流。
    • 你可以利用reduce方法将流中所有的元素迭代合并成一个结果,例如求和或查找最大元素。
    • filter和map等操作是无状态的,它们并不存储任何状态。reduce等操作要存储状态才能计算出一个值。sorted和distinct等操作也要存储状态,因为它们需要把流中的所有元素缓存起来才能返回一个新的流。这种操作称为有状态操作。
    • 流有三种基本的原始类型特化:IntStream、DoubleStream和LongStream。它们的操
      作也有相应的特化。
    • 流不仅可以从集合创建,也可从值、数组、文件以及iterate与generate等特定方法
      创建。
    • 无限流是没有固定大小的流。
      在这里插入图片描述
3.1 付诸实践

在本节中,你会将迄今学到的关于流的知识付诸实践。我们来看一个不同的领域:执行交易的交易员。你的经理让你为八个查询找到答案。你能做到吗?我们在5.5.2节给出了答案,但你应 该自己先尝试一下作为练习。

(1) 找出2011年发生的所有交易,并按交易额排序(从低到高)。 (2) 交易员都在哪些不同的城市工作过?
(3) 查找所有来自于剑桥的交易员,并按姓名排序。
(4) 返回所有交易员的姓名字符串,按字母顺序排序。
(5) 有没有交易员是在米兰工作的?
(6) 打印生活在剑桥的交易员的所有交易额。 (7) 所有交易中,最高的交易额是多少?
(8) 找到交易额最小的交易。

类定义:

package org.study.streamApi;

public class Trader {
    private final String name;
    private final String city;

    public Trader(String n, String c) {
        this.name = n;
        this.city = c;
    }

    public String getName() {
        return this.name;
    }

    public String getCity() {
        return this.city;
    }

    public String toString() {
        return "Trader:" + this.name + " in " + this.city;
    }
}

class Transaction {
    private final Trader trader;
    private final int year;
    private final int value;

    public Transaction(Trader trader, int year, int value) {
        this.trader = trader;
        this.year = year;
        this.value = value;
    }

    public Trader getTrader() {
        return trader;
    }

    public int getYear() {
        return year;
    }

    public int getValue() {
        return value;
    }

    @Override
    public String toString() {
        return "{" + trader + ", " +
                "year:" + year + ", " +
                "value:" + value + '}';
    }
}

逻辑编写:

package org.study.streamApi;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public class CaseTask {
    public static void main(String[] args) {
        Trader raoul = new Trader("Raoul", "Cambridge");
        Trader mario = new Trader("Mario","Milan");
        Trader alan = new Trader("Alan","Cambridge");
        Trader brian = new Trader("Brian","Cambridge");

        List<Transaction> transactions = Arrays.asList(
                new Transaction(brian, 2011, 300),
                new Transaction(raoul, 2012, 1000),
                new Transaction(raoul, 2011, 400),
                new Transaction(mario, 2012, 710),
                new Transaction(mario, 2012, 700),
                new Transaction(alan, 2012, 950)
        );

        //(1) 找出2011年发生的所有交易,并按交易额排序(从低到高)。
        transactions.stream().filter(d -> d.getYear() == 2011).sorted(Comparator.comparing(Transaction::getValue)).forEach(System.out::println);

        //(2) 交易员都在哪些不同的城市工作过?
        transactions.stream().map(t -> t.getTrader().getCity()).distinct().forEach(System.out::println);

        //(3) 查找所有来自于剑桥的交易员,并按姓名排序。
        transactions.stream().map(t -> t.getTrader()).filter(t -> t.getCity().equals("Cambridge")).distinct().sorted(Comparator.comparing(Trader::getName)).forEach(System.out::println);

        //(4) 返回所有交易员的姓名字符串,按字母顺序排序。
        transactions.stream().map(t -> t.getTrader().getName()).distinct().sorted((x, y) -> x.compareTo(y)).forEach(System.out::println);

        //(5) 有没有交易员是在米兰工作的?
        boolean milan = transactions.stream().anyMatch(t -> t.getTrader().getCity().equals("Milan"));
        System.out.println(milan);

        //(6) 打印生活在剑桥的交易员的所有交易额。
        transactions.stream().filter(t -> t.getTrader().getCity().equals("Cambridge")).map(Transaction::getValue).forEach(System.out::println);

        //(7) 所有交易中,最高的交易额是多少?
        Optional<Integer> maxValue = transactions.stream().map(Transaction::getValue).reduce(Integer::max);
        System.out.println(maxValue.get());

        //(8) 找到交易额最小的交易。
        Optional<Integer> minValue = transactions.stream().map(Transaction::getValue).reduce(Integer::min);
        System.out.println(minValue.get());
    }
}

4. 收集器作为高级归约

  • 对流调用collect方法将对流中的元素触发一个归约操作(由Collector来参数化)
  • Collectors实用类提供了很多静态工厂方法, 可以方便地创建常见收集器的实例,只要拿来用就可以了

在这里插入图片描述
在这里插入图片描述

类定义:

package org.study.fourStreamApi;

public class Dish {
    private final String name;
    private final boolean vegetarian;

    private final int calories;
    private final Type type;

    public Dish(String name, boolean vegetarian, int calories, Type type) {
        this.name = name;
        this.vegetarian = vegetarian;
        this.calories = calories;
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public boolean isVegetarian() {
        return vegetarian;
    }

    public int getCalories() {
        return calories;
    }

    public Type getType() {
        return type;
    }

    public enum Type { MEAT, FISH, OTHER}

    @Override
    public String toString() {
        return name;
    }
}

业务逻辑:

package org.study.fiveStreamApiCollectors;

import org.study.fourStreamApi.Dish;

import java.util.*;

import static java.util.Comparator.comparingInt;
import static java.util.stream.Collectors.*;

public class TestSteamApiCollectors {
    static List<Dish> menu = Arrays.asList(
            new Dish("pork", false, 800, Dish.Type.MEAT),
            new Dish("beef", false, 700, Dish.Type.MEAT),
            new Dish("chicken", false, 400, Dish.Type.MEAT),
            new Dish("french fries", true, 530, Dish.Type.OTHER),
            new Dish("rice", true, 350, Dish.Type.OTHER),
            new Dish("season fruit", true, 120, Dish.Type.OTHER),
            new Dish("pizza", true, 550, Dish.Type.OTHER),
            new Dish("prawns", false, 300, Dish.Type.FISH),
            new Dish("salmon", false, 450, Dish.Type.FISH)
    );

    public static void main(String[] args) {
        test1();
        test2();
        test3();
        test4();
    }

    public static void test1() {
        //归约
        Long howManyDishes = menu.stream().collect(counting());
        Long howManyDishes2 = menu.stream().count();
        System.out.println(howManyDishes);
        System.out.println(howManyDishes2);

        Optional<Dish> mostCalorieDish = menu.stream().collect(maxBy(comparingInt(Dish::getCalories)));
        System.out.println(mostCalorieDish.get());
    }

    public static void test2() {
        //汇总
        //菜单列表的总热量
        Integer totalCalories = menu.stream().collect(summingInt(Dish::getCalories));
        System.out.println(totalCalories);

        //菜单列表的平均热量
        double avgCalories = menu.stream().collect(averagingInt(Dish::getCalories));
        System.out.println(avgCalories);

        //通过一次summarizing操作你可以就数出菜单中元素的个数,并得 到菜肴热量总和、平均值、最大值和最小值
        IntSummaryStatistics menuStatistics = menu.stream().collect(summarizingInt(Dish::getCalories));
        System.out.println(menuStatistics);
    }

    public static void test3() {
        //连接字符串
        String shortMenu = menu.stream().map(Dish::getName).collect(joining());
        System.out.println(shortMenu);
        //String shortMenu2 = menu.stream().collect(joining());
        //System.out.println(shortMenu2);

        //连接字符串,加分隔符
        String shortMenu3 = menu.stream().map(Dish::getName).collect(joining(", "));
        System.out.println(shortMenu3);
    }

    public enum CaloricLevel {DIET, NORMAL, FAT}

    public static void test4() {
        //分组
        //简单分类
        Map<Dish.Type, List<Dish>> dishesByType = menu.stream().collect(groupingBy(Dish::getType));
        System.out.println(dishesByType);

        //复杂分类 - 单级分类
        Map<CaloricLevel, List<Dish>> dishesByCaloricLevel = menu.stream().collect(groupingBy(dish -> {
            if (dish.getCalories() <= 400) return CaloricLevel.DIET;
            else if (dish.getCalories() <= 700) return
                    CaloricLevel.NORMAL;
            else return CaloricLevel.FAT;
        }));
        System.out.println(dishesByCaloricLevel);

        //多级分类
        Map<Dish.Type, Map<CaloricLevel, List<Dish>>> dishesByTypeCaloricLevel =
                menu.stream().collect(
                        groupingBy(Dish::getType,
                                groupingBy(
                                        dish -> {
                                            if (dish.getCalories() <= 400) return CaloricLevel.DIET;
                                            else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
                                            else return CaloricLevel.FAT;
                                        }
                                )));
        System.out.println(dishesByTypeCaloricLevel);

        Map<Dish.Type, Set<CaloricLevel>> caloricLevelsByType =
                menu.stream().collect(
                        groupingBy(Dish::getType,
                                mapping(
                                        dish -> {
                                            if (dish.getCalories() <= 400) return CaloricLevel.DIET;
                                            else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
                                            else return CaloricLevel.FAT;
                                        },
                                        toSet())
                        ));
        System.out.println(caloricLevelsByType);

        //按子组收集数据
        //例如,要数一数菜单中每类菜有多少个
        Map<Dish.Type, Long> typesCount = menu.stream().collect(
                groupingBy(Dish::getType, counting()));
        System.out.println(typesCount);
        //查找每个子组中热量最高的Dish
        Map<Dish.Type, Dish> mostCaloricByType =
                menu.stream()
                        .collect(groupingBy(Dish::getType,
                                        collectingAndThen(
                                                maxBy(comparingInt(Dish::getCalories)),
                                                Optional::get)
                                )
                        );
        System.out.println(mostCaloricByType);
    }
}

5. 用Optional取代null

null带来的问题:

  • 它是错误之源,NullPointerException是目前Java程序开发中最典型的异常。
  • 它会使你的代码膨胀,它让你的代码充斥着深度嵌套的null检查,代码的可读性糟糕透顶。
  • 它自身是毫无意义的,null自身没有任何的语义,尤其是,它代表的是在静态类型语言中以一种错误的方式对 3 缺失变量值的建模。
  • 它破坏了Java的哲学。Java一直试图避免让程序员意识到指针的存在,唯一的例外是:null指针。
  • 它在Java的类型系统上开了个口子,null并不属于任何类型,这意味着它可以被赋值给任意引用类型的变量

用例:
在这里插入图片描述
在这里插入图片描述
model:

package org.study.sixOptional;

import java.awt.desktop.OpenFilesEvent;
import java.util.Optional;

public class Person {
    private Optional<Car> car;

    public Person() {
    }

    public Person(Car car) {
        this.car = Optional.ofNullable(car);
    }

    public Optional<Car> getCar() {
        return car;
    }
}

class Car {
    private Optional<Insurance> insurance;

    public Car() {
    }

    public Car(Insurance insurance) {
        this.insurance = Optional.ofNullable(insurance);
    }

    public Optional<Insurance> getInsurance() {
        return insurance;
    }
}

class Insurance {
    private String name;

    public Insurance(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

test代码:

package org.study.sixOptional;

import java.util.Optional;

public class TestCase {
    public static void main(String[] args) {
        testCreateOptional();
        testGetOptionalValueForMap();
        testGetCarInsuranceName();
        testOptionalFilter();
    }

    public static void testCreateOptional() {
        //1. 声明一个空的Optional
        Optional<Car> optCar = Optional.empty();

        //2. 一句一个非空值创建Optional
        Optional<Car> car = Optional.of(new Car());
        //如果car是一个null,这段代码会立即抛出一个NullPointerException,而不是等到你 试图访问car的属性值时才返回一个错误。
        //Optional<Car> car2 = Optional.of(null);

        //3.可接受null的Optional
        Optional<Car> nullCar = Optional.ofNullable(null);
        // get方法在遭遇到空的Optional对象时也会抛出异常。 java.util.NoSuchElementException
        //nullCar.get();
    }

    public static void testGetOptionalValueForMap() {
        Insurance xiaoMi = new Insurance("xiao mi");
        Optional<Insurance> optInsurance = Optional.ofNullable(xiaoMi);
        Optional<String> name = optInsurance.map(Insurance::getName);
        System.out.println(name.isPresent() ? name.get() : "");
    }


    public static void testGetCarInsuranceName(){
        Person person = new Person(new Car(new Insurance("xiaomi")));
        String name = getCarInsuranceName(person);
        System.out.println(name);

        String optName = getCarInsuranceName2(person);
        String optName2 = getCarInsuranceName2(null);
        System.out.println(optName);
        System.out.println(optName2);

    }
    public static String getCarInsuranceName(Person person) {
        return person.getCar().get().getInsurance().get().getName();
    }

    public static String getCarInsuranceName2(Person person) {
        Optional<Person> optPerson = Optional.ofNullable(person);
        return optPerson.flatMap(Person::getCar).flatMap(Car::getInsurance).map(Insurance::getName).orElse("Unkown");
    }

    public static void testOptionalFilter(){
        Insurance xiaoMi = new Insurance("xiao mi");
        Optional<Insurance> optInsurance = Optional.ofNullable(xiaoMi);
        optInsurance.filter(insurance -> "xiao mi".equals(insurance.getName())).ifPresent(x -> System.out.println("ok"));
    }

}

在这里插入图片描述

6. 新的日期和时间API:LocalDate、LocalTime、Instant、Duration以及Period

package org.study.sevenTime;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.util.TimeZone;

import static java.time.temporal.TemporalAdjusters.*;

public class TestCase {
    public static void main(String[] args) {
        testLocalData();
        testLocalTime();
        testLocalDateTime();
        testInstant();
        testCreateDurationAndPeriod();
        testTemporalAdjuster();
        stringParseToTimeObj();
        objParseToString();
        addTimeZone();
    }

    public static void testLocalData() {
        LocalDate date = LocalDate.of(2014, 3, 18);  //2014-03-18
        int year = date.getYear();
        System.out.println(year);  //2014

        Month month = date.getMonth();
        System.out.println(month); //MARCH

        int day = date.getDayOfMonth();
        System.out.println(day);   //18

        DayOfWeek dow = date.getDayOfWeek();
        System.out.println(dow);   //TUESDAY

        int len = date.lengthOfMonth();
        System.out.println(len);   //31

        boolean leap = date.isLeapYear(); //是否闰年
        System.out.println(leap);  //false

        //获取当前日期  2014:3:18
        LocalDate now = LocalDate.now();

        //传递一个TemporalField参数获取时间
        int now_year = date.get(ChronoField.YEAR);
        int now_month = date.get(ChronoField.MONTH_OF_YEAR);
        int now_day = date.get(ChronoField.DAY_OF_MONTH);
        System.out.println(now_year + ":" + now_month + ":" + now_day);  //2014:3:18
    }

    public static void testLocalTime() {
        LocalTime time = LocalTime.of(13, 45, 20); //13:45:20
        int hour = time.getHour();
        int minute = time.getMinute();
        int second = time.getSecond();
        System.out.println(time);  //13:45:20
    }

    public static void testLocalDateTime() {
        LocalDate date = LocalDate.parse("2014-03-18");
        LocalTime time = LocalTime.parse("13:45:20");

        // 2014-03-18T13:45:20
        LocalDateTime dt1 = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45, 20);
        LocalDateTime dt2 = LocalDateTime.of(date, time);
        LocalDateTime dt3 = date.atTime(13, 45, 20);
        LocalDateTime dt4 = date.atTime(time);
        LocalDateTime dt5 = time.atDate(date);

        System.out.println(dt1);  //2014-03-18T13:45:20
        System.out.println(dt2);  //2014-03-18T13:45:20
        System.out.println(dt3);  //2014-03-18T13:45:20
        System.out.println(dt4);  //2014-03-18T13:45:20
        System.out.println(dt5);  //2014-03-18T13:45:20


        LocalDate date1 = dt1.toLocalDate();
        LocalTime time1 = dt1.toLocalTime();
        System.out.println(date1);
        System.out.println(time1);
    }

    public static void testInstant() {
        //时间戳对象,用于获取当前时刻时间戳
        // 获取当前时间的Instant对象
        Instant now = Instant.now();

        // 将Instant转换为时间戳(毫秒)
        long timestamp = now.toEpochMilli();

        // 输出时间戳
        System.out.println("当前时间的时间戳(毫秒):" + timestamp);
    }

    public static void testCreateDurationAndPeriod() {
        //1. 创建对象
        Duration threeMinutes = Duration.ofMinutes(3);
        Duration threeMinutes2 = Duration.of(3, ChronoUnit.MINUTES);
        Period tenDays = Period.ofDays(10);
        Period threeWeeks = Period.ofWeeks(3);
        Period twoYearsSixMonthsOneDay = Period.of(2, 6, 1);

        //2.你可以创建两个LocalTimes对象、两个LocalDateTimes对象,或者两个Instant对象之间的duration
        //Duration d1 = Duration.between(time1, time2);
        //Duration d1 = Duration.between(dateTime1, dateTime2);
        //Duration d2 = Duration.between(instant1, instant2);
    }

    public static void handleTime() {
        //注意,下面的这段代码中所有的方法都返回一个修改了属性的对象。它们都不会修改原来的对象!
        LocalDate date1 = LocalDate.of(2014, 3, 18); //2014-03-18
        LocalDate date2 = date1.withYear(2011);                             //2011-03-18
        LocalDate date3 = date2.withDayOfMonth(25);                         //2011-03-25
        LocalDate date4 = date3.with(ChronoField.MONTH_OF_YEAR, 9);//2011-09-25

        LocalDate date5 = LocalDate.of(2014, 3, 18);  //2014-03-18
        LocalDate date6 = date1.plusWeeks(1);                     //2014-03-25
        LocalDate date7 = date2.minusYears(3);                 //2011-03-25
        LocalDate date8 = date3.plus(6, ChronoUnit.MONTHS);      //2011-09-25
    }

    public static void testTemporalAdjuster() {
        //截至目前,你所看到的所有日期操作都是相对比较直接的。有的时候,你需要进行一些更加 复杂的操作,比如,将日期调整到下个周日、下个工作日,或者是本月的最后一天。
        //这时,你可 2 以使用重载版本的with方法,向其传递一个提供了更多定制化选择的TemporalAdjuster对象, 更加灵活地处理日期。对于最常见的用例,日期和时间API已经提供了大量预定义的 TemporalAdjuster。
        //你可以通过TemporalAdjuster类的静态工厂方法访问它们,如下所示
        LocalDate date1 = LocalDate.of(2014, 3, 18);
        LocalDate date2 = date1.with(nextOrSame(DayOfWeek.SUNDAY));
        LocalDate date3 = date2.with(lastDayOfMonth());
        System.out.println(date1);
        System.out.println(date2);
        System.out.println(date3);
    }

    public static void stringParseToTimeObj() {
        //一旦传递的字 符串参数无法被解析为合法的LocalDate或LocalTime对象,这两个parse方法都会抛出一个继 承自RuntimeException的DateTimeParseException异常。
        LocalDate date = LocalDate.parse("2014-03-18");
        LocalTime time = LocalTime.parse("13:45:20");

        System.out.println(date);
        System.out.println(time);

        LocalDateTime dateTime = LocalDateTime.parse("2014-03-18T16:00:01");
        System.out.println(dateTime);
    }

    public static void objParseToString() {
        //obj to string
        LocalDate date = LocalDate.of(2014, 3, 18); //2014-03-18
        String s1 = date.format(DateTimeFormatter.BASIC_ISO_DATE);         //20140318
        String s2 = date.format(DateTimeFormatter.ISO_LOCAL_DATE);         //2014-03-18

        System.out.println(s1);
        System.out.println(s2);

        //string to obj
        LocalDate date1 = LocalDate.parse("20140318",
                DateTimeFormatter.BASIC_ISO_DATE);
        LocalDate date2 = LocalDate.parse("2014-03-18",
                DateTimeFormatter.ISO_LOCAL_DATE);

        //自定义格式化时间
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
        LocalDate date3 = LocalDate.of(2014, 3, 18);

        String formattedDate = date3.format(formatter);    //18/03/2014
        System.out.println(formattedDate);

        LocalDate date4 = LocalDate.parse(formattedDate, formatter); //obj 2014-03-18
        System.out.println(date4);
    }

    public static void addTimeZone() {
        //1.获取zoneid
        ZoneId romeZone = ZoneId.of("Europe/Rome");  //Europe/Rome
        ZoneId shanghai = TimeZone.getDefault().toZoneId();   //Asia/Shanghai

        //为时间点添加时区信息
        LocalDate date = LocalDate.of(2014, Month.MARCH, 18);
        ZonedDateTime zdt1 = date.atStartOfDay(romeZone);
        System.out.println(zdt1);  //2014-03-18T00:00+01:00[Europe/Rome]

        LocalDateTime dateTime = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45);
        ZonedDateTime zdt2 = dateTime.atZone(romeZone);
        System.out.println(zdt2);  //2014-03-18T13:45+01:00[Europe/Rome]

        Instant instant = Instant.now();
        ZonedDateTime zdt3 = instant.atZone(romeZone);
        System.out.println(zdt3);   //2024-05-29T10:02:34.381001+02:00[Europe/Rome]
    }
}
  • 18
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值