015Java8新特性

Java8引入了全新的日期时间API,解决了旧API的诸多问题,提供了如LocalDate、LocalTime和LocalDateTime等不可变对象。Instant类代表时间线上的一个点,便于机器处理。DateTimeFormatter支持日期时间的格式化。Stream API提供了高效的数据处理方式,包括并行流,与Collection不同,Stream关注计算而非存储。Lambda表达式简化了匿名内部类的使用,函数式接口如Predicate和Function等增强了函数式编程的支持。
摘要由CSDN通过智能技术生成

JDK8中新日期时间API:

背景:

java.util.Date类和Calendar面临的问题是:

​ 可变性:像日期和时间这样的类应该是不可变的。

​ 偏移性:Date中的年份是从1900开始的,而月份都从0开始。

​ 格式化:格式化只对Date有用, Calendar则不行。

​ 此外,它们也不是线程安全的;不能处理闰秒等。

Java8吸收了Joda-Time的精华,以一个新的开始为Java创建优秀的API。

新的java.time中包含了所有关于本地日期(LocalDate)、本地时间(LocalTime)、本地日期时间(LocalDateTime)、时区(ZonedDateTime)和持续时间(Duration)的类。

历史悠久的Date类新增了toInstant()方法,用于把Date转换成新的表示形式。这些新增的本地化时间日期API大大简化了日期时间和本地化的管理。

新时间日期API:

java.time – 包含值对象的基础包

java.time.chrono – 提供对不同的日历系统的访问

java.time.format – 格式化和解析时间和日期

java.time.temporal – 包括底层框架和扩展特性

java.time.zone – 包含时区支持的类

LocalDate、LocalTime、LocalDateTime类是其中较重要的几个类,它们的实例是不可变的对象,分别表示使用 ISO-8601日历系统的日期、时间、日期和时间。

它们提供了简单的本地日期或时间,并不包含当前的时间信息,也不包含与时区相关的信息。

LocalDate代表IOS格式(yyyy-MM-dd)的日期,可以存储 生日、纪念日等日期。

LocalTime表示一个时间,而不是日期。

LocalDateTime是用来表示日期和时间的,这是一个最常用的类之一。

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

方法描述
now() / * now(ZoneId zone)静态方法, 根据当前时间创建对象/指定时区的对象
of()静态方法, 根据指定日期/时间创建对象
getDayOfMonth()/getDayOfYear()获得月份天数(1-31) /获得年份天数(1-366)
getDayOfWeek()获得星期几(返回一个 DayOfWeek 枚举值)
getMonth()获得月份, 返回一个 Month 枚举值
getMonthValue() / getYear()获得月份(1-12) /获得年份
getHour()/getMinute()/getSecond()获得当前对象对应的小时、 分钟、 秒
withDayOfMonth()/withDayOfYear()/ withMonth()/withYear()将月份天数、 年份天数、 月份、 年份修改为指定的值并返回新的对象
plusDays(), plusWeeks(), plusMonths(), plusYears(),plusHours()向当前对象添加几天、 几周、 几个月、 几年、 几小时
minusMonths() / minusWeeks()/ minusDays()/minusYears()/minusHours()从当前对象减去几月、 几周、 几天、 几年、 几小时
//now():获取当前的日期、时间、日期+时间
LocalDate localDate = LocalDate.now();//2021-03-28
LocalTime localTime = LocalTime.now();//12:42:25.316
LocalDateTime localDateTime = LocalDateTime.now();//2021-03-28T12:42:25.316

//of():获取设置指定的年、月、日、时、分、秒的对象。没有偏移量
LocalDateTime localDateTime1 = LocalDateTime.of(2020, 10, 6, 13, 23, 43);
//2020-10-06T13:23:43

瞬时:Instant:

Instant:时间线上的一个瞬时点。

这可能被用来记录应用程序中的事件时间戳。在处理时间和日期的时候,我们通常会想到年,月,日,时,分,秒。

然而,这只是时间的一个模型,是面向人类的。第二种通用模型是面向机器的,或者说是连续的。

在此模型中,时间线中的一个点表示为一个很大的数,这有利于计算机处理。在UNIX中,这个数从1970年开始,以秒为的单位;同样的,在Java中,也是从1970年开始,但以毫秒为单位。

java.time包通过值类型Instant提供机器视图,不提供处理人类意义上的时间单位。Instant表示时间线上的一点,而不需要任何上下文信息,例如,时区。

概念上讲,它只是简单的表示自1970年1月1日0时0分0秒( UTC)开始的秒数。 因为java.time包是基于纳秒计算的,所以Instant的精度可以达到纳秒级。

(1 ns = 10-9 s) 1秒 = 1000毫秒 =106微秒=109纳秒

注:时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。

方法描述
now()静态方法, 返回默认UTC时区的Instant类的对象
ofEpochMilli(long epochMilli)静态方法数之后的,Instant 返回在类的对象
1970-01-01 00:00:00基础上加上指定毫秒
atOffset(ZoneOffset offset)结合即时的偏移来创建一个OffsetDateTime
toEpochMilli()返回1970-01-01 00:00:00到当前时间的毫秒数, 即为时间戳
//now():获取本初子午线对应的标准时间//2021-02-18T07:29:41.719Z
Instant instant = Instant.now();

//添加时间的偏移量//2021-02-18T15:32:50.611+08:00
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));

//toEpochMilli():获取自1970年1月1日0时0分0秒(UTC)开始的毫秒数  ---> Date类的getTime()
long milli = instant.toEpochMilli();

//ofEpochMilli():通过给定的毫秒数,获取Instant实例  -->Date(long millis)
Instant instant1 = Instant.ofEpochMilli(1550475314878L);

格式化与解析日期或时间:

java.time.format.DateTimeFormatter类:该类提供了三种格式化方法:

预定义的标准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME

本地化相关的格式。如: ofLocalizedDateTime(FormatStyle.LONG)

自定义的格式。如: ofPattern(“yyyy-MM-dd hh:mm:ss”)

方 法描 述
ofPattern(String pattern)静态方法,返回一个指定字符串格式的DateTimeFormatter
format(TemporalAccessor t)格式化一个日期、时间,返回字符串
parse(CharSequence text)将指定格式的字符序列解析为一个日期、时间
//方式一:预定义的标准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
//格式化:日期-->字符串
LocalDateTime localDateTime = LocalDateTime.now();
String str1 = formatter.format(localDateTime);
System.out.println(localDateTime);
System.out.println(str1);//2021-02-18T15:42:18.797

//解析:字符串 -->日期
TemporalAccessor parse = formatter.parse("2019-02-18T15:42:18.797");
System.out.println(parse);

//方式二:
//本地化相关的格式。如:ofLocalizedDateTime()
//FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT :适用于LocalDateTime
DateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
//格式化
String str2 = formatter1.format(localDateTime);
System.out.println(str2);//2019年2月18日 下午03时47分16秒


//本地化相关的格式。如:ofLocalizedDate()
//FormatStyle.FULL / FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT : 适用于LocalDate
DateTimeFormatter formatter2 = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);
//格式化
String str3 = formatter2.format(LocalDate.now());
System.out.println(str3);//2019-2-18


//重点: 方式三:自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)
DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
//格式化
String str4 = formatter3.format(LocalDateTime.now());
System.out.println(str4);//2019-02-18 03:52:09

//解析
TemporalAccessor accessor = formatter3.parse("2019-02-18 03:52:09");
System.out.println(accessor);

其它日期时间API :

ZoneId:该类中包含了所有的时区信息,一个时区的ID,如 Europe/Paris

ZonedDateTime:一个在ISO-8601日历系统时区的日期时间,如 2007-12-03T10:15:30+01:00 Europe/Paris。

其中每个时区都对应着ID,地区ID都为“ {区域}/{城市}” 的格式,例如:Asia/Shanghai等

Clock:使用时区提供对当前即时、 日期和时间的访问的时钟。

持续时间:Duration,用于计算两个“时间” 间隔

日期间隔:Period,用于计算两个“日期” 间隔

TemporalAdjuster: 时间校正器。有时我们可能需要获取例如:将日期调整到“下一个工作日”等操作。

TemporalAdjusters: 该类通过静态方法(firstDayOfXxx()/lastDayOfXxx()/nextXxx())提供了大量的常用TemporalAdjuster的实现

// ZoneId:类中包含了所有的时区信息
// ZoneId的getAvailableZoneIds():获取所有的ZoneId
Set<String> zoneIds = ZoneId.getAvailableZoneIds();
for (String s : zoneIds) {
	System.out.println(s);
}
// ZoneId的of():获取指定时区的时间
LocalDateTime localDateTime = LocalDateTime.now(ZoneId.of("Asia/Tokyo"));
System.out.println(localDateTime);

// ZonedDateTime:带时区的日期时间
// ZonedDateTime的now():获取本时区的ZonedDateTime对象
ZonedDateTime zonedDateTime = ZonedDateTime.now();
System.out.println(zonedDateTime);

// ZonedDateTime的now(ZoneId id):获取指定时区的ZonedDateTime对象
ZonedDateTime zonedDateTime1 = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
System.out.println(zonedDateTime1);

// Duration:用于计算两个“时间”间隔,以秒和纳秒为基准
LocalTime localTime = LocalTime.now();
LocalTime localTime1 = LocalTime.of(15, 23, 32);

// between():静态方法,返回Duration对象,表示两个时间的间隔
Duration duration = Duration.between(localTime1, localTime);
System.out.println(duration);
System.out.println(duration.getSeconds());
System.out.println(duration.getNano());
LocalDateTime localDateTime = LocalDateTime.of(2016, 6, 12, 15, 23, 32);
LocalDateTime localDateTime1 = LocalDateTime.of(2017, 6, 12, 15, 23, 32);
Duration duration1 = Duration.between(localDateTime1, localDateTime);
System.out.println(duration1.toDays());

// Period:用于计算两个“日期”间隔,以年、月、日衡量
LocalDate localDate = LocalDate.now();
LocalDate localDate1 = LocalDate.of(2028, 3, 18);
Period period = Period.between(localDate, localDate1);
System.out.println(period);
System.out.println(period.getYears());
System.out.println(period.getMonths());
System.out.println(period.getDays());
Period period1 = period.withYears(2);
System.out.println(period1);

// TemporalAdjuster:时间校正器
// 获取当前日期的下一个周日是哪天?
TemporalAdjuster temporalAdjuster = TemporalAdjusters.next(DayOfWeek.SUNDAY);
LocalDateTime localDateTime = LocalDateTime.now().with(temporalAdjuster);
System.out.println(localDateTime);

// 获取下一个工作日是哪天?
LocalDate localDate = LocalDate.now().with(new TemporalAdjuster() {
	@Override
	public Temporal adjustInto(Temporal temporal) {
		LocalDate date = (LocalDate) temporal;
		if (date.getDayOfWeek().equals(DayOfWeek.FRIDAY)) {
			return date.plusDays(3);
		} else if (date.getDayOfWeek().equals(DayOfWeek.SATURDAY)) {
			return date.plusDays(2);
		} else {
			return date.plusDays(1);
		}
	}
});
System.out.println("下一个工作日是: " + localDate);

与传统日期处理的转换:

To 遗留类From 遗留类
java.time.Instant
与java.util.Date
Date.
from(instant)
date.
toInstant()
java.time.Instant
与java.sql.Timestamp
Timestamp.
from(instant)
timestamp.
toInstant()
java.time.ZonedDateTime
与 java.util.GregorianCalendar
GregorianCalendar.
from(zonedDateTime)
cal.
toZonedDateTime()
java.time.LocalDate
与java.sql.Time
Date.
valueOf(localDate)
date.
toLocalDate()
java.time.LocalTime
与java.sql.Time
Date.
valueOf(localDate)
date.
toLocalTime()
java.time.LocalDateTime
与 java.sql.Timestamp
Timestamp.
valueOf(localDateTime)
timestamp.
toLocalDateTime()
java.time.ZoneId
与java.util.TimeZone
Timezone.
getTimeZone(id)
timeZone.
toZoneId()
java.time.format.DateTimeFormatter
与 java.text.DateFormat
formatter.
toFormat()

JDK8中注解的新特性:

Java8对注解处理提供了两点改进:可重复的注解及可用于类型的注解。此外,反射也得到了加强,在Java8中能够得到方法参数的名称。

这会简化标注在方法参数上的注解。

类型注解:

JDK1.8之后,关于元注解@Target的参数类型ElementType枚举值多了两个:

TYPE_PARAMETER,TYPE_USE。

在Java8之前,注解只能是在声明的地方所使用,Java8开始,注解可以应用在任何地方。

ElementType.TYPE_PARAMETER表示该注解能写在类型变量的声明语句中(如: 泛型声明) 。

ElementType.TYPE_USE表示该注解能写在使用类型的任何语句中。

JVM中字符串常量池存放位置说明:

jdk 1.6:字符串常量池存储在方法区(永久区)

jdk 1.7:字符串常量池存储在堆空间

jdk 1.8:字符串常量池存储在方法区(元空间)

并行流与串行流:

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

相比较串行的流, 并行的流可以很大程度上提高程序的执行效率。

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

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

Lambda表达式:

Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。

使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。

Lambda 表达式: 在Java 8 语言中引入的一种新的语法元素和操作符。

这个操作符为 “->” , 该操作符被称为 Lambda 操作符或箭头操作符。

它将 Lambda 分为两个部分:

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

右侧: 指定了 Lambda 体, 是抽象方法的实现逻辑,也即Lambda 表达式要执行的功能。

语法格式一: 无参,无返回值
语法格式二: Lambda 需要一个参数,但是没有返回值。
语法格式三: 数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
语法格式四: Lambda 若只需要一个参数时, 参数的小括号可以省略
语法格式五: Lambda 需要两个或以上的参数,多条执行语句,并且可以有返回值
语法格式六: 当 Lambda 体只有一条语句时, return 与大括号若有,都可以省略

类型推断:

Lambda 表达式中的参数类型都是由编译器推断得出的。

Lambda表达式中无需指定类型,程序依然可以编译,这是因为 javac 根据程序的上下文,在后台推断出了参数的类型。

Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的“类型推断” 。

函数式(Functional)接口:

只包含一个抽象方法的接口,称为函数式接口。

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

(若 Lambda 表达式抛出一个受检异常(即:非运行时异常),那么该异常需要在目标接口的抽象方法上进行声明)。

我们可以在一个接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口。

同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。

在java.util.function包下定义了Java 8 的丰富的函数式接口

如何理解函数式接口:

Java从诞生日起就是一直倡导“一切皆对象”, 在Java里面面向对象(OOP)编程是一切。但是随着python、 scala等语言的兴起和新技术的挑战, Java不得不做出调整以便支持更加广泛的技术要求,也即java不但可以支持OOP还可以支持OOF(面向函数编程)。

在函数式编程语言当中,函数被当做一等公民对待。

在将函数作为一等公民的编程语言中, Lambda表达式的类型是函数。

但是在Java8中,有所不同。

在Java8中, Lambda表达式是对象,而不是函数,它们必须依附于一类特别的对象类型——函数式接口。

简单的说,在Java8中, Lambda表达式就是一个函数式接口的实例。

这就是Lambda表达式和函数式接口的关系。

也就是说,只要一个对象是函数式接口的实例,那么该对象就可以用Lambda表达式来表示。

所以以前用匿名实现类表示的现在都可以用Lambda表达式来写。

作为参数传递 Lambda 表达式:

为了将 Lambda 表达式作为参数传递,接收Lambda表达式的参数类型必须是与该 Lambda 表达式兼容的函数式接口的类型。

Java 内置四大核心函数式接口:

函数式接口参数类型返回类型用途
Consumer
消费型接口
Tvoid对类型为 void accept(T t) T的对象应用操作,包含方法:
Supplier
供给型接口
T返回类型为T的对象,包含方法: T get()
Function<T, R>
函数型接口
TR对类型为 果是R类型的对象。包含 T的对象应用操作,并返回结果。结 方法: R apply(T t)
Predicate
断定型接口
Tboolean确定类型为 boolean 值。包含 T的对象是否满足某约束,并返回 方法: boolean test(T t)

其他函数式接口:

函数式接口参数类型返回类型用途
BiFunction<T, U, R>T, UR对类型为 T, U 参数应用操作, 返回 R 类型的结 果。
包含方法为: R apply(T t, U u);
UnaryOperator
(Function子接口)
TT对类型为 结果。 包含方法 T的对象进行一元运算 为:
T apply(T t),; 并返回T类型的
BinaryOperator
(BiFunction 子接口)
T, TT对类型为 结果。 包含方法 T的对象进行二元运算 为: T apply(T,t1并返回 , T t2);T类型的
BiConsumer<T, U>T, Uvoid对类型为T, U 参数应用操作。 包含方法为:
void accept(T t, U u)
BiPredicate<T,U>T,Uboolean包含方法为: boolean test(T t,U u)
ToIntFunction
ToLongFunction
ToDoubleFunction
Tint long double分别计算int、 long、 double值的函数
IntFunction
LongFunction DoubleFunction
int long doubleR参数分别为int、 long、 double 类型的函数

方法引用:

方法引用(Method References):

当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!

方法引用可以看做是Lambda表达式深层次的表达。

换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖。

要求:

实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致!

格式: 使用操作符 “::” 将类(或对象) 与 方法名分隔开来。

如下三种主要使用情况:

对象::实例方法名

类::静态方法名

类::实例方法名

注意:

当函数式接口方法的第一个参数是需要引用方法的调用者,并且第二个参数是需要引用方法的参数(或无参数)时: ClassName::methodName

构造器引用:

格式: ClassName::new

与函数式接口相结合,自动与函数式接口中方法兼容。

可以把构造器引用赋值给定义的方法,要求构造器参数列表要与接口中抽象方法的参数列表一致!

且方法的返回值即为构造器对应类的对象。

数组引用:

格式: type[] :: new

Stream API:

Java8中有两大最为重要的改变。

第一个是 Lambda 表达式;另外一个则是 Stream API。

Stream API ( java.util.stream) 把真正的函数式编程风格引入到Java中。

这是目前为止对Java类库最好的补充,因为Stream API可以极大提供Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。

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

也可以使用 Stream API 来并行执行操作。

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

为什么要使用Stream API:

实际开发中,项目中多数数据源都来自于Mysql, Oracle等。

但现在数据源可以更多了,有MongDB, Radis等,而这些NoSQL的数据就需要Java层面去处理。

Stream 和 Collection 集合的区别:

Collection 是一种静态的内存数据结构,而 Stream 是有关计算的。

前者是主要面向内存,存储在内存中,后者主要是面向 CPU,通过 CPU 实现计算。

什么是 Stream:

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

“集合讲的是数据, Stream讲的是计算!”

注意:

①Stream 自己不会存储元素。

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

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

Stream 的操作三个步骤:

1- 创建 Stream

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

2- 中间操作

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

3- 终止操作(终端操作)

​ 一旦执行终止操作, 就执行中间操作链,并产生结果。之后,不会再被使用

创建 Stream方式一:通过集合

Java8 中的 Collection 接口被扩展,提供了两个获取流的方法:

default Stream stream() : 返回一个顺序流

default Stream parallelStream() : 返回一个并行流

创建 Stream方式二:通过数组

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

static Stream stream(T[] array): 返回一个流重载形式,能够处理对应基本类型的数组:

public static IntStream stream(int[] array)

public static LongStream stream(long[] array)

public static DoubleStream stream(double[] array)

创建 Stream方式三:通过Stream的of()

可以调用Stream类静态方法 of(), 通过显示值创建一个流。

它可以接收任意数量的参数。

public static Stream of(T… values) : 返回一个流

创建 Stream方式四:创建无限流

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

迭代

public static Stream iterate(final T seed, final UnaryOperator f)

生成

public static Stream generate(Supplier s)

Stream 的中间操作:

多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!

而在终止操作时一次性全部处理,称为“惰性求值” 。

1-筛选与切片:
方 法描 述
filter(Predicate p)接收 Lambda , 从流中排除某些元素
distinct()筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
limit(long maxSize)截断流,使其元素不超过给定数量
skip(long n)跳过元素,返回一个扔掉了前 个空流。与 limit(n) 互补 n 个元素的流。若流中元素不足 n 个,则返回一
2-映 射
方法描述
map(Function f)接收一个函数作为参数,该函数会被应用到每个元 素上,并将其映射成一个新的元素。
mapToDouble(ToDoubleFunction f)接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 DoubleStream。
mapToInt(ToIntFunction f)接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 IntStream。
mapToLong(ToLongFunction f)接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 LongStream。
flatMap(Function f)接收一个函数作为参数,将流中的每个值都换成另 一个流,然后把所有流连接成一个流
3-排 序
方法描述
sorted()产生一个新流,其中按自然顺序排序
sorted(Comparator com)产生一个新流,其中按比较器顺序排序

Stream 的终止操作:

终端操作会从流的流水线生成结果。

其结果可以是任何不是流的值,例如: List、 Integer,甚至是 void 。

流进行了终止操作后,不能再次使用。

1-匹配与查找
方法描述
allMatch(Predicate p)检查是否匹配所有元素
anyMatch(Predicate p)检查是否至少匹配一个元素
noneMatch(Predicate p)检查是否没有匹配所有元素
findFirst()返回第一个元素
findAny()返回当前流中的任意元素
方法描述
count()返回流中元素总数
max(Comparator c)返回流中最大值
min(Comparator c)返回流中最小值
forEach(Consumer c)内部迭代(使用 Collection 接口需要用户去做迭代, 称为外部迭代。相反, Stream API 使用内部迭 代——它帮你把迭代做了)
2-归约(备注: map 和 reduce 的连接通常称为 map-reduce 模式,因 Google用它来进行网络搜索而出名。 )
方法描述
reduce(T iden, BinaryOperator b)可以将流中元素反复结合起来,得到一 个值。返回 T
reduce(BinaryOperator b)可以将流中元素反复结合起来,得到一 个值。返回 Optional
3-收集
方 法描 述
collect(Collector c)将流转换为其他形式。接收一个 Collector 接口的实现,用于给Stream中元素做汇总 的方法

Collector 接口中方法的实现决定了如何对流执行收集的操作(如收集到 List、 Set、Map)。

另外, Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:

方法返回类型作用
toListList把流中元素收集到List
List emps= list.stream().collect(Collectors.toList());
toSetSet把流中元素收集到Set
Set emps= list.stream().collect(Collectors.toSet());
toCollectionCollection把流中元素收集到创建的集合
Collection emps =list.stream().collect(Collectors.toCollection(ArrayList::new));
countingLong计算流中元素的个数
long count = list.stream().collect(Collectors.counting());
summingIntInteger对流中元素的整数属性求和
int total=list.stream().collect(Collectors.summingInt(Employee::getSalary));
averagingIntDouble计算流中元素Integer属性的平均值
double avg = list.stream().collect(Collectors.averagingInt(Employee::getSalary));
summarizingIntIntSummaryStatistics收集流中Integer属性的统计值。 如:平 均值
int SummaryStatisticsiss= list.stream().collect(Collectors.summarizingInt(Employee::getSalary));
joiningString连接流中每个字符串
String str= list.stream().map(Employee::getName).collect(Collectors.joining());
maxByOptional根据比较器选择最大值
Optionalmax= list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary)));
minByOptional根据比较器选择最小值
Optional min = list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary)));
reducing归约产生的类型从一个作为累加器的初始值开始, 利用BinaryOperator与流中元素逐 个结合,从而归约成单个值
int total=list.stream().collect(Collectors.reducing(0, Employee::getSalar, Integer::sum));
collectingAndThen转换函数返回的类型包裹另一个收集器,对其结果转 换函数
int how= list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
groupingByMap<K, List>根据某属性值对流分组,属性为K, 结果为V
Map<Emp.Status, List> map= list.stream() .collect(Collectors.groupingBy(Employee::getStatus));
partitioningByMap<Boolean, List>根据true或false进行分区
Map<Boolean,List> vd = list.stream().collect(Collectors.partitioningBy(Employee::getManage));

Optional类:

到目前为止,臭名昭著的空指针异常是导致Java应用程序失败的最常见原因。

以前,为了解决空指针异常, Google公司著名的Guava项目引入了Optional类,Guava通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代码。

受到Google Guava的启发, Optional类已经成为Java 8类库的一部分。

Optional 类(java.util.Optional) 是一个容器类, 它可以保存类型T的值, 代表这个值存在。

或者仅仅保存null,表示这个值不存在。

原来用 null 表示一个值不存在,现在 Optional 可以更好的表达这个概念。

并且可以避免空指针异常。

Optional类的Javadoc描述如下:

这是一个可以为null的容器对象。

如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。

Optional提供很多有用的方法,这样我们就不用显式进行空值检测。

创建Optional类对象的方法:

Optional.of(T t) : 创建一个 Optional 实例, t必须非空;

Optional.empty() : 创建一个空的 Optional 实例

Optional.ofNullable(T t): t可以为null

判断Optional容器中是否包含对象:

boolean isPresent() : 判断是否包含对象

void ifPresent(Consumer<? super T> consumer) : 如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它。

获取Optional容器的对象:

T get(): 如果调用对象包含值,返回该值,否则抛异常

T orElse(T other) : 如果有值则将其返回,否则返回指定的other对象。

T orElseGet(Supplier<? extends T> other) : 如果有值则将其返回,否则返回由Supplier接口实现提供的对象。

T orElseThrow(Supplier<? extends X> exceptionSupplier) : 如果有值则将其返回,否则抛出由Supplier接口实现提供的异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值