天天看点

JDK新特性JDK1.5新特性JDK1.7新特性JDK1.8新特性Stream API

枚举概述: 就是一个类只能存在几个固定的对象,那么这个就是枚举.我们就可以使用这些对象可以表示一些固定的值.

举例:一周只有7天,一年只有12个月等。

定义枚举类要用关键字enum

所有枚举类都是Enum的子类

枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是可以省略的,但是如果枚举类有其他的东西,这个分号就不能省略。建议不要省略

枚举类可以有构造器,但必须是private的,它默认的也是private的。枚举项的用法比较特殊:枚举(“”);

枚举类也可以有抽象方法,但是枚举项必须重写该方法

枚举在switch语句中的使用

int ordinal() 返回枚举项的序号

int compareTo(E o) 比较两个枚举项的 返回的是两个枚举项序号的 差值

String name() 获取枚举项的名称

String toString()获取枚举项的名称

<T> T valueOf(Class<T> type,String name) 用来获取指定的枚举项 参数1:枚举类对应的字节码对象 参数2 枚举项的名称

values() 获取所有的枚举项

此方法虽然在JDK文档中查找不到,但每个枚举类都具有该方法,它遍历枚举类的所有枚举值非常方便

1:

public static void main(String[] args) {

// 测试

Direction front = Direction.FRONT ;

Direction behind = Direction.BEHIND;

Direction left = Direction.LEFT ;

Direction right = Direction.RIGHT ;

System.out.println(front.ordinal());

System.out.println(behind.ordinal());

System.out.println(left.ordinal());

System.out.println(right.ordinal());

System.out.println("----------------------------------");

System.out.println(front.compareTo(right));

System.out.println(front.name());

System.out.println(front.toString());

System.out.println(front);

// <T> T valueOf(Class<T> type,String name): 用来获取指定的枚举项

// type: 表示的是对应的枚举的字节码文件对象

// name: 就是枚举项的名称

Direction direction = Direction.valueOf(Direction.class, "RIGHT") ;

System.out.println(direction);

Direction[] directions = Direction.values() ;

for(Direction d : directions){

System.out.println(d);

}

2

public enum Direction {

FRONT("前"), AFTER("后"), LEFT("后"),RIGHT("右"); //下面如果有代码,; 分号不要省略,每个枚举项,用逗号隔开

private Direction(String name){}

//public class Direction {

// //表示前后左右四个固定的值

// //ctrl+shift+U 转换大小写

// public static final org.westos.demo8.Direction FRONT = new org.westos.demo8.Direction("前");

// public static final org.westos.demo8.Direction AFTER = new org.westos.demo8.Direction("后");

// public static final org.westos.demo8.Direction LEFT = new org.westos.demo8.Direction("左");

// public static final org.westos.demo8.Direction RIGHT = new org.westos.demo8.Direction("右");

// public String name;

//

// private Direction(String name) {

// this.name = name;

// }

//}

public class MyTest {

Direction front = Direction.FRONT;

Direction after = Direction.AFTER;

Direction left = Direction.LEFT;

Direction right = Direction.RIGHT;

System.out.println(after);

System.out.println(left);

System.out.println(right);

为了增强对数值的阅读性,如我们经常把数据用逗号分隔一样。JDK7提供了_对数据分隔。

举例:

int x = 100_1000;

注意事项:

不能出现在进制标识和数值之间

不能出现在数值开头和结尾

不能出现在小数点旁边

LocalDate、 LocalTime、 LocalDateTime类的实例是不可变的对象,分别表示使用 ISO-8601日历系统的日期、时间、日期和时间它们提供了简单的日期或时间,并不包含当前的时间信息。也不包含与时区相关的信息。

注: ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示法

这些新增的日期时间API都在 java.time包下

1通过静态方法 now();

例如:LocalDateTime ldt = LocalDateTime.now();

1获取对象的方法 now()

注意默认获取出来的是当前的美国时间和我们相差八个小时

Instant ins = Instant.now();

System.out.println(ins);

我们在东八区 所以可以加8个小时 就是我们的北京时间

Instant中设置偏移量的方法:atOffset() 设置偏移量

OffsetDateTime time = ins.atOffset(ZoneOffset.ofHours(8));

System.out.println(time);

3.获取系统默认时区时间的方法atZone()

方法的参数是要一个时区的编号可以通过时区编号类获取出来

ZoneId.systemDefault()获取本地的默认时区ID

ZonedDateTime zonedDateTime = ins.atZone(ZoneId.systemDefault());

System.out.println(zonedDateTime);

4.get系列的方法

getEpochSecond() 获取从1970-01-01 00:00:00到当前时间的秒值

getNano()方法是把获取到的当前时间的秒数 换算成纳秒

long epochSecond = ins.getEpochSecond();//获取从1970-01-01 00:00:00到当前时间的秒值

getNano()方法是把获取到的当前时间的豪秒数 换算成纳秒 比如当前时间是2018-01-01 14:00:20:30

那就把30豪秒换算成纳秒 int nano = ins.getNano();

ofEpochSecond()方法 给计算机元年增加秒数

例如 Instant instant = Instant.ofEpochSecond(5);

System.out.println(instant);

单位换算

0.1 毫秒 = 10 的5次方纳秒 = 100000 纳秒

1 毫秒 = 1000 微妙 = 1000000 纳秒

Duration类中静态方法between()

Instant start = Instant.now();

for(int i=0;i<1000L;i++){

System.out.println("循环内容");

Instant end = Instant.now();

静态方法:between() 计算两个时间的间隔,默认是秒

Duration between = Durati’on.between(start, end);

Duration中的toMillis()方法:将秒转成毫秒

System.out.println(between.toMillis());

Period类 中的静态方法between()

计算两个日期之间的间隔

LocalDate s = LocalDate.of(1985, 03, 05);

LocalDate now = LocalDate.now();

Period be = Period.between(s, now);

System.out.println(be.getYears());间隔了多少年

System.out.println(be.getMonths());间隔了多少月

System.out.println(be.getDays());间隔多少天

一般我们用该接口的一个对应的工具类 TemporalAdjusters中的一些常量,来指定日期

System.out.println(now);

1 使用TemporalAdjusters自带的常量来设置日期

LocalDate with = now.with(TemporalAdjusters.lastDayOfYear());

System.out.println(with);

2 采用TemporalAdjusters中的next方法来指定日期

LocalDate date = now.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));

System.out.println(date);

例如:TemporalAdjusters.next(DayOfWeek.SUNDAY) 本周的星期天

例如:TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY) 下一周的星期一

3 采用自定义的方式来指定日期 比如指定下个工作日

LocalDateTime ldt = LocalDateTime.now();

LocalDateTime workDay = ldt.with(new TemporalAdjuster() {br/>@Override

public Temporal adjustInto(Temporal temporal) {

//向下转型

LocalDateTime ld = (LocalDateTime) temporal;

//获取这周的星期几

DayOfWeek dayOfWeek = ld.getDayOfWeek();

if (dayOfWeek.equals(DayOfWeek.FRIDAY)) {

return ld.plusDays(3);//如果这天是星期五,那下个工做日就加3天

} else if (dayOfWeek.equals(DayOfWeek.SATURDAY)) {

return ld.plusDays(2);//如果这天是星期六,那下个工做日就加2天

} else {

//其他就加一天

return ld.plusDays(1);

});

1.获取对象的方式,通过静态方法ofPattern("yyyy-MM-dd");

DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd");

LocalDateTime now = LocalDateTime.now();

2.format()方法把一个日期对象的默认格式 格式化成指定的格式

String format1 = dateFormat.format(now);

System.out.println(format1);

3.格式化日期 方式2使用日期类中的format方法 传入一个日期格式化类对象

4.使用自定义的日期格式格式化字符串

DateTimeFormatter timeFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");//自定义一个日期格式

String time = now1.format(timeFormat);

把一个日期字符串转成日期对象

使用日期类中的parse方法传入一个日期字符串,传入对应的日期格式化类

LocalDateTime parse = LocalDateTime.parse(time, timeFormat);

System.out.println(parse);

用法和 LocalDate、 LocalTime、 LocalDateTime 一样 只不过ZonedDate,ZonedTime、ZonedDateTime 这三个带有当前系统的默认时区

1.获取世界各个地方的时区的集合 的方法getAvailableZoneIds()

使用ZoneID中的静态方法getAvailableZoneIds();来获取

例如:Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();

2.获取系统默认时区的ID

ZoneId zoneId = ZoneId.systemDefault(); //Asia/Shanghai

3.获取带有时区的日期时间对象

//创建日期对象

//获取不同国家的日期时间根据各个地区的时区ID名创建对象

ZoneId timeID = ZoneId.of("Asia/Shanghai");

//根据时区ID获取带有时区的日期时间对象

ZonedDateTime time = now.atZone(timeID);

//方式2 通过时区ID 获取日期对象

LocalDateTime now2 = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));

System.out.println(now2);

Lambda 是一个匿名函数,我们可以把 Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。

public interface MyInterface {

void show(int a,int b);

//JDK1.8之后提供了一种新的语法 叫做 Lambda表达式,可以简化我们对匿名内部类的写法,也可以作为参数传递

//可以使用匿名内部类来创建该接口的一个子类对象

MyInterface myInterface = new MyInterface() {br/>@Override

public void show(int a, int b) {

System.out.println(a + b);

};

myInterface.show(10, 20);

//上面匿名内部类的写法,我可以用Lambda表达式来简化

//Lambda 引入了一个箭头 -> 符号,将我们的表达式分为左右两部分

//箭头左边,就是接口中抽象方法的参数列表,箭头右边,是你对接口中的抽象方法的具体的重写逻辑

//参数列表中的数据类型 可以省略不写

MyInterface myInterface3 = (x, y) -> System.out.println(x + y);

//当然你可以写上参数的,数据类型

MyInterface myInterface2 = (int x, int y) -> System.out.println(x + y);

public class MyTest2 {

MyInterface2 myInterface2 = new MyInterface2() {br/>@Override

public int test(int a, int b) {

return a + b;

private static void myTest(MyInterface myInterface) {

myInterface.show(10,20);

通过上面的对比,发现Lambda表达式式书写起来更为简洁

那我们具体来看一下Lambda表达式的书写语法

Lambda 表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “ ->” , 该操作符被称为 Lambda 操作符或箭头操作符。它将 Lambda 分为两个部分:

左侧: 指定了 Lambda 表达式需要的所有参数

右侧: 指定了 Lambda 体,即 Lambda 表达式要执行的功能。

public interface MyInteface3 {

void test();

void show();

new MyInteface3(){br/>@Override

public void test() {

//Lambda 需要 函数式接口的支持

// 函数式接口:这个接口中,仅仅只有 一个抽象方法

// 函数式接口可以使用注解 @FunctionalInterface 来检测这个接口是不是函数式接口

public class MyTest3 {

上述 Lambda 表达式中的参数类型都是由编译器推断得出的。 Lambda 表达式中无需指定类型,程序依然可以编译,这是因为 javac 根据程序的上下文,在后台推断出了参数的类型。 Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的“类型推断”.

Lambda表达式就是对函数式接口的一种简写方式,所以只有是函数式接口,我们才能用Lambda表达式.再换句话说,Lambda表达式需要函数式接口的支持,那函数式接口我们可以自己定义,当然JDK1.8也给我们提供了一些现成的函数式接口.

你可以通过 Lambda 表达式来创建该接口的对象

我们可以在任意函数式接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口.

函数式接口 参数类型 返回类型 用途

Consumer<T>

消费型接口 T void 对类型为T的对象应用操

作,包含方法:

void accept(T t)

Supplier<T>

供给型接口 无 T 返回类型为T的对象,包

含方法: T get();

Function<T, R>

函数型接口

T R 对类型为T的对象应用操

作,并返回结果。结果

是R类型的对象。包含方

法: R apply(T t);

Predicate<T> 断言型接口

T boolean 确定类型为T的对象是否

满足某约束,并返回

boolean 值。包含方法

boolean test(T t);

BiFunction<T,U,R>

T U R 对类型为 T, U 参数应用

操作, 返回 R 类型的结

果。 包含方法为

R apply(T t, U u);

UnaryOperator<T>

(Function的子接口)

T T 对类型为T的对象进行一

元运算, 并返回T类型的

结果。 包含方法为

T apply(T t);

BinaryOperator<T>

(BiFunction的子接口) T T T 对类型为T的对象进行二

T apply(T t1, T t2);

BiConsumer<T,U>

T U void 对类型为T, U 参数应用

操作。 包含方法为

void accept(T t, U u)

ToIntFunction<T>

ToLongFunction<T>

ToDoubleFunction<T>

T int

long

double 分 别 计 算 int 、 long 、

double、 值的函数

IntFunction<R>

LongFunction<R>

DoubleFunction<R>

int

double R 参数分别为int、 long、

double 类型的函数

Stream 是 Java8 中处理集合的关键抽象概念,

它可以指定你希望对集合进行的操作,

可以执行非常复杂的查找、过滤和映射数据等操作。

使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。

简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。

是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。

集合讲的是数据,流讲的是计算!

注意:

①Stream 自己不会存储元素。

②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。

③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

Stream 的操作三个步骤

1.创建 Stream

一个数据源(如:集合、数组),获取一个流

 2.中间操作

一个中间操作链,对数据源的数据进行处理

 3.终止操作(终端操作)

一个终止操作,执行中间操作链,并产生结果

 default Stream<E> stream() : 返回一个顺序流

 default Stream<E> parallelStream() : 返回一个并行流

2.Java8 中的 Arrays 的静态方法 stream() 可以获取数组流:

 static <T> Stream<T> stream(T[] array): 返回一个流

重载形式,能够处理对应基本类型的数组:

public static IntStream stream(int[] array)

 public static LongStream stream(long[] array)

 public static DoubleStream stream(double[] array)

3.由值创建流,可以使用静态方法 Stream.of(), 通过显示值创建一个流。它可以接收任意数量的参数。

 public static<T> Stream<T> of(T... values) : 返回一个流

4.由函数创建流:创建无限流可以使用静态方法 Stream.iterate()和Stream.generate(), 创建无限流。

public static<T> Stream<T> iterate(final T seed, finalUnaryOperator<T> f) 迭代

public static<T> Stream<T> generate(Supplier<T> s) 生成

筛选与切片

filter(Predicate p) 过滤 接收 Lambda , 从流中排除某些元素。

distinct() 去重,通过流所生成元素的 hashCode() 和 equals() 去除重复元素

limit(long maxSize) 截断流,使其元素不超过给定数量。

skip(long n) 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补

2.映射

map(Function f) 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。

flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流.

mapToDouble(ToDoubleFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。

mapToInt(ToIntFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream。

mapToLong(ToLongFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream。

3.排序

sorted() 产生一个新流,其中按自然顺序排序 元素实现Compareble接口

sorted(Comparator comp) 产生一个新流,其中按比较器顺序排序 传入一个比较器

终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是 void 。

并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。

Java 8 中将并行进行了优化,我们可以很容易的对数据进行并行操作。

Stream API 可以声明性地通过 parallel() 与sequential() 在并行流与顺序流之间进行切换。

public Employee() {

//**Stream 的操作三个步骤

//1. 创建 Stream

//一个数据源(如:集合、数组),获取一个流

//2. 中间操作

//一个中间操作链,对数据源的数据进行处理

//3. 终止操作(终端操作)

//一个终止操作,执行中间操作链,并产生结果

//我们会创建流跟集合关联起来,关联起来后,我们是想要使用这个流对集合中的元素,进行一些列的中间操作

//1. 筛选与切片

//filter(Predicate p) 过滤 接收 Lambda ,从流中排除某些元素。

//distinct() 去重,通过流所生成元素的 hashCode () 和 equals () 去除重复元素

//limit( long maxSize)截断流,使其元素不超过给定数量。

//skip( long n)跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit (n) 互补

List<Employee> emps = Arrays.asList(

new Employee(102, "李四", 59, 6666.66),

new Employee(101, "张三", 18, 9999.99),

new Employee(103, "王五", 28, 3333.33),

new Employee(104, "赵六", 8, 7777.77),

new Employee(105, "田七", 38, 5555.55)

);

new Employee(104, "赵六", 8, 7777.771),

new Employee(104, "赵六", 8, 7777.772),

new Employee(104, "赵六", 8, 7777.773),

继续阅读