3 minute read

Java8是大部分公司使用的一个版本,我们来学习总结一下新特性吧。

接口相关

  1. 可以使用static关键字。让接口的方法成为该接口的私有方法,无法被继承,只能通过接口调用。
  2. 可以使用default关键字。让接口可以被继承,重写,但是也可以选择不重写,从而使用默认的方式。
public interface Food {
    void eat();

    //无法被继承
    static void hello() {
        System.out.println("hello world!");
    }

    //可以继承,也可以不继承,然后使用默认的方法
    default void say() {
        System.out.println("这是default");
    }
}
public class Test implements Food {

    @Override
    public void eat() {
        System.out.println("eat");
    }

    public static void main(String[] args) {
        Food.hello();
        Test test = new Test();
        test.eat();
        test.say();
    }
}

结果

hello world!
eat
这是default

Lambda表达式

提供函数式编程,格式为(parameters) -> expression

    //Java8之前的排序方式
    List<Integer> list = Arrays.asList(3, 2, 1, 6);
    Collections.sort(list, new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o1 - o2;
        }
    });
    //lambda表达式实现上述排序
    Collections.sort(list, (o1, o2) -> (o1 - o2));
    //可以使用外部变量,但是不允许修改,默认拥有final属性
    int k=1;
    Collections.sort(list,(o1,o2)->(o1-k));
    // 还可以进一步优化
    list.sort((o1, o2) -> o1 - o2);

forEach

    List<String> list = Arrays.asList("1", "2", "3");
    //java8之前
    for (String s : list) {
        System.out.println(s);
    }
    //forEach,使用lambda表达式
    list.forEach((s) -> System.out.println(s));

::

传递方法或者构造函数引用

    List<String> list = Arrays.asList("1", "2", "3");
    //java8之前
    for (String s : list) {
        System.out.println(s);
    }
    //forEach,下面用了::
    list.forEach(System.out::println);

Stream

把数据想象成水管里的水流,Java流就是对这些水流进行处理,包括筛选、排序、统计、计数等。

Stream 操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回 Stream 本身,这样你就可以将多个操作依次串起来

   public class Main {
    public static void main(String[] args) {
        List<String> stringList = new ArrayList<>();
        stringList.add("ddd2");
        stringList.add("aaa2");
        stringList.add("bbb1");
        stringList.add("aaa1");
        stringList.add("bbb3");
        stringList.add("ccc");
        stringList.add("bbb2");
        stringList.add("ddd1");
        // 中间操作 过滤
        stringList.stream().filter((s) -> s.startsWith("a")).forEach(System.out::println);
        // 中间操作 排序
        stringList.stream().sorted().filter((s) -> s.startsWith("a")).forEach(System.out::println);
        // 中间操作 映射
        stringList.stream().map(String::toUpperCase).sorted((a, b) -> b.compareTo(a)).forEach(System.out::println);
        // 最终操作 匹配
        boolean anyStartsWithA = stringList.stream().anyMatch((s) -> s.startsWith("a"));
        System.out.println(anyStartsWithA);
        boolean allStartsWithA = stringList.stream().allMatch((s) -> s.startsWith("a"));
        System.out.println(allStartsWithA);
        boolean noneStartsWithZ = stringList.stream().noneMatch((s) -> s.startsWith("z"));
        System.out.println(noneStartsWithZ);
        // 最终操作 计数
        long startsWithB = stringList.stream().filter((s) -> s.startsWith("b")).count();
        System.out.println(startsWithB);
        // 最终操作 规约
        Optional<String> reduced = stringList.stream().sorted().reduce((s1, s2) -> s1 + "#" + s2);
        reduced.ifPresent(System.out::println);

        // 并行流
        int max = 1000000;
        List<String> values = new ArrayList<>(max);
        for (int i = 0; i < max; i++) {
            UUID uuid = UUID.randomUUID();
            values.add(uuid.toString());
        }
        //并行排序
        long s0 = System.nanoTime();
        values.parallelStream().sorted();
        long s1 = System.nanoTime();
        long millis1 = TimeUnit.NANOSECONDS.toMillis(s1 - s0);
        System.out.println(String.format("parallel sort took: %d ms", millis1));
    }
}

Optional

为了解决NullPointException问题。

传统的解决方法是调用前判断是否为空再调用。

class Zoo{
    private Dog dog;
}

class Dog{
    private int age;
}
Zoo zoo=getZoo();
if(!zoo=null){
    Dog dog=zoo.getDog();
    if(dog!=null){
        int age=dog.getAge();
        //do something
    }
}
//Optional则是这么实现的
Optional.ofNullable(zoo).map(o->o.getDog()).map(d->d.getAge()).ifPrensent(age->//do something)

其他例子

public class Main {
    public static void main(String[] args) {
        // of():为非null的值创建一个Optional
        Optional<String> optional = Optional.of("bam");
        // isPresent():如果值存在返回true,否则返回false
        // true
        System.out.println(optional.isPresent());
        // get():如果Optional有值则将其返回,否则抛出NoSuchElementException
        // bam
        System.out.println(optional.get());
        // orElse():如果有值则将其返回,否则返回指定的其它值
        // bam
        System.out.println(optional.orElse("fallback"));
        // ifPresent():如果Optional实例有值则为其调用consumer,否则不做处理
        // b
        optional.ifPresent((s) -> System.out.println(s.charAt(0)));
    }
}

Time类

Java.time包括了LocalDateTime,LocalDate,LocalTime

Clock

public class Main {
    public static void main(String[] args) {
        Clock clock = Clock.systemDefaultZone();
        long millis = clock.millis();
        System.out.println(millis);
        Instant instant = clock.instant();
        System.out.println(instant);
        Date legacyDate = Date.from(instant);
        System.out.println(legacyDate);
    }
}

Timezones

public class Main {
    public static void main(String[] args) {
        System.out.println(ZoneId.getAvailableZoneIds());
        ZoneId zone1 = ZoneId.of("Europe/Berlin");
        ZoneId zone2 = ZoneId.of("Brazil/East");
        System.out.println(zone1.getRules());
        System.out.println(zone2.getRules());
    }
}

LocalTime

LocalTime 定义了一个没有时区信息的时间

public class Main {
    public static void main(String[] args) {
        ZoneId zone1 = ZoneId.of("Europe/Berlin");
        ZoneId zone2 = ZoneId.of("Brazil/East");
        LocalTime now1 = LocalTime.now(zone1);
        LocalTime now2 = LocalTime.now(zone2);
        System.out.println(now1.isBefore(now2));

        long hoursBetween = ChronoUnit.HOURS.between(now1, now2);
        long minutesBetween = ChronoUnit.MINUTES.between(now1, now2);

        System.out.println(hoursBetween);
        System.out.println(minutesBetween);
    }
}

LocalTime 提供了多种工厂方法来简化对象的创建,包括解析时间字符串

public class Main {
    public static void main(String[] args) {
        LocalTime late = LocalTime.of(23, 59, 59);
        System.out.println(late);
        DateTimeFormatter germanFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).withLocale(Locale.GERMAN);

        LocalTime leetTime = LocalTime.parse("13:37", germanFormatter);
        System.out.println(leetTime);
    }
}

LocalDate

public class Main {
    public static void main(String[] args) {
        LocalDate today = LocalDate.now();
        System.out.println("今天的日期: " + today);
        LocalDate tomorrow = today.plus(1, ChronoUnit.DAYS);
        System.out.println("明天的日期: " + tomorrow);
        LocalDate yesterday = tomorrow.minusDays(2);
        System.out.println("昨天的日期: " + yesterday);
        LocalDate independenceDay = LocalDate.of(2019, Month.MARCH, 12);
        DayOfWeek dayOfWeek = independenceDay.getDayOfWeek();
        System.out.println("今天是周几:" + dayOfWeek);
    }
}

LocalDateTime

public class Main {
    public static void main(String[] args) {
        LocalDateTime sylvester = LocalDateTime.of(2014, Month.DECEMBER, 31, 23, 59, 59);
        DayOfWeek dayOfWeek = sylvester.getDayOfWeek();
        System.out.println(dayOfWeek);
        Month month = sylvester.getMonth();
        System.out.println(month);
        long minuteOfDay = sylvester.getLong(ChronoField.MINUTE_OF_DAY);
        System.out.println(minuteOfDay);
    }
}

内置函数式接口

Predicate

判断一个参数是否符合要求

    Predicate<String> predicate = s -> s.length() > 0;
    // true
    System.out.println(predicate.test("test"));
    // false
    System.out.println(predicate.negate().test("foo"));

Function

接受参数并生成结果,可用于将多个函数连接在一起。

    Function<String, Integer> toInteger = Integer::valueOf;
    Function<String, String> backToString = toInteger.andThen(String::valueOf);
    System.out.println(backToString.apply("123"));

Supplier

产生给定泛型类型的结果

public class People {
    void hello() {
        System.out.println("hello");
    }
}
public class Main {
    public static void main(String[] args) {
        Supplier<People> personSupplier = People::new;
        personSupplier.get().hello();
    }
}

Consumer

消费某个对象

public class Main {
    public static void main(String[] args) {
        Consumer<Integer> square = x -> System.out.println("平方计算 : " + x * x);
        square.accept(2);

        //当前值
        Consumer<Integer> consumer1 = x -> System.out.println("当前值 : " + x);
        //相加
        Consumer<Integer> consumer2 = x -> {
            System.out.println("相加 : " + (x + x));
        };
        //相乘
        Consumer<Integer> consumer3 = x -> System.out.println("相乘 : " + x * x);
        //andThen拼接
        consumer1.andThen(consumer2).andThen(consumer3).accept(1);

        //可以用于变量list赋值
        List<People> list = new ArrayList<>();
        list.add(new People("xiaoming"));
        list.add(new People("xiahong"));
        list.forEach(o -> o.setName("hello"));
    }
}

Tags:

Categories:

Updated: