为啥放着Java16不用,都在用Java8?看完Java8的新特
函数式接口
java内置四大核心函数式接口
image.png
核心接口子接口
image.png
//Consumer<T>消费型接口
public static void test1(){
cost(8888, (m) -> System.out.println("共消费:" + m + "元"));
}
public static void cost(double money,Consumer<Double> con){
con.accept(money);
}
//Supplier<T> 供给型接口
public static void test2(){
List<Integer> list = getNumList(8, () -> (int)(Math.random() * 100));
for (Integer integer : list) {
System.out.println(integer);
}
}
//产生指定数量的整数,放入集合中
public static List<Integer> getNumList(int num,Supplier<Integer> sup){
List<Integer> list = new ArrayList<>();
for (int i = 0; i < num; i++) {
Integer n = sup.get();
list.add(n);
}
return list;
}
//Function<T,R> 函数型接口
public static void test3(){
String string = strHandler("函数型接口测试 ", (str) -> str.trim().substring(0, 5));
System.out.println(string);
}
//用于处理字符串
public static String strHandler(String str,Function<String, String> fun){
return fun.apply(str);
}
//Predicate<T> 断言型接口
public static void test4(){
List<String> list = Arrays.asList("hello","Lambda","ok");
List<String> strList = filterStr(list, (s) -> s.length() > 3);
for (String string : strList) {
System.out.println(string);
}
}
//将满足条件的字符串,放入集合中
public static List<String> filterStr(List<String> list, Predicate<String> pre){
List<String> strList = new ArrayList<>();
for (String str : list) {
if (pre.test(str)) {
strList.add(str);
}
}
return strList;
}
方法引用与构造器引用
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!(实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!)方法引用:使用操作符 “::” 将方法名和对象或类的名字分隔开来。
如下三种主要使用情况:
- 对象::实例方法
- 类::静态方法
- 类::实例方法
使用注意事项:
1.Lambda 体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致。
2.若Lambda 参数列表中第一个参数是实例方法调用者,第二个参数是实例方法的参数 可以使用 ClassName :: method
//对象的引用 :: 实例方法名
@Test
public void test1(){
PrintStream ps = System.out;
Consumer<String> con = (str) -> ps.println(str);
con.accept("Hello World!");
Consumer<String> con2 = ps::println;
con2.accept("Hello World!");
Consumer<String> con3 = System.out::println;
}
//类名 :: 静态方法名
@Test
public void test2(){
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
Comparator<Integer> com2 = Integer::compare;
}
//类名 :: 实例方法名
@Test
public void test3(){
BiPredicate<String, String> bp = (x, y) -> x.equals(y);
System.out.println(bp.test("abcde", "abcde"));
BiPredicate<String, String> bp2 = String::equals;
System.out.println(bp2.test("abc", "abc"));
Function<Employee, String> fun = (e) -> e.show();
System.out.println(fun.apply(new Employee()));
Function<Employee, String> fun2 = Employee::show;
System.out.println(fun2.apply(new Employee()));
}
构造器引用:
- 构造器参数列表要与接口中抽象方法的参数列表一致,格式为 类名::new
- 与函数式接口相结合,自动与函数式接口中方法兼容
public void test1(){
Supplier<Employee> sup = () -> new Employee();
System.out.println(sup.get());
Supplier<Employee> sup1 = Employee::new;
System.out.println(sup1.get());
}
数组引用
- 格式:类型[] :: new
public void test1(){
Function<Integer, String[]> fun = (args) -> new String[args];
String[] strs = fun.apply(10);
System.out.println(strs.length);
Function<Integer, String[]> fun1 = String[] :: new;
String[] strs = fun1.apply(20);
System.out.println(strs.length);
}
Stream API
Stream 是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列Stream 自己不会存储元素,不会改变源对象且返回一个持有结果的新Stream,操作是延迟执行的Stream API 提供了一种高效且易于使用的处理数据的方式
Stream API 的操作步骤:
1.创建Stream数据源
2.中间操作
3.终止操作(终端操作)
创建Stream
- 方式一:Java8中的Collection接口被扩展.提供两个获取流的方法
default Stream stream() : 返回一个顺序流
default Stream parallelStream() : 返回一个并行流
注:Collection接口下的所有实现类或者子接口都可以通过 对象.stream() 的方法返回一个流给Stream对象
- 方式二:Java8中的Arrays的静态方法 stream() 可以获取数组流
static Stream stream(T[] array)
注:从数组中获取流可以使用 Arrays.stream(数组名) 来进行获取
- 方式三:Stream类的静态方法 Stream.of() 通过显示值创建一个流,可接收任意数量的参数
public static Stream of(T… values) : 返回一个流
使用 Stream stream = Stream.of(“a”,“b”,“c”) 获取流
- 方式四:静态方法 Stream.iterate() 和 Stream.generate() 创建无限流
迭代 public static Stream iterate(final T seed, final UnaryOperator f)
生成 public static Stream generate(Supplier s)
public void test1(){
//1.可以通过Collection系列集合提供的stream() 或parallelStream()
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
//2.通过Arrays中静态方法 stream() 获取数组流
Person[] persons = new Person[10];
Stream<Person> stream2 = Arrays.stream(persons);
//3.通过Stream类中的静态方法 of()
Stream<String> stream3 = Stream.of("a","b","c");
//4.创建无限流
//迭代
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
stream4.limit(8).forEach(System.out :: println);
//生成
Stream.generate(() -> Math.random()).limit(6)
.forEach(System.out :: println);
}
中间操作
筛选与切片方法
- filter(Perticate p) — 接收 Lambda , 从流中排除某些元素
- distinct() — 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
- limit(Long n) — 截断流,使其元素不超过给定数量
- skip(Long n) —— 跳过元素,返回一个扔掉了前 n 个元素的流,若流中元素不足 n 个,则返回一个空流,与 limit(n) 互补
映射方法
- map(Function f) — 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
- flatMap(Function f) — 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
- mapToDouble(ToDoubleFunction f) — 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream
- mapToInt(ToIntFunction f) — 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的IntStream
- mapToLong(ToLongFunction f) — 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的LongStream
排序方法
- sorted() — 产生一个新流,按自然顺序排序
- sorted(Comparator com) — 产生一个新流,按比较器顺序定制排序
/**
* Stream API的中间操作
*/
public class TestSteamAPI2 {
List<Person> persons = Arrays.asList(
new Person(2, "钱四", 24),
new Person(1, "张三", 33),
new Person(2, "李四", 24),
new Person(3, "王五", 65),
new Person(4, "赵六", 26),
new Person(4, "赵六", 26),
new Person(5, "陈七", 27)
);
//内部迭代,由Stream API完成
@Test
public void test1(){
//中间操作,不会执行任何操作
Stream<Person> stream = persons.stream()
.filter((e) -> {
System.out.println("Stream的中间操作");
return e.getAge() > 25;
});
//终止操作,一次性执行全部内容,即"惰性求值"
stream.forEach(System.out :: println);
}
//外部迭代
@Test
public void test2(){
Iterator<Person> iterator = persons.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
//limit,截断
@Test
public void test3(){
persons.stream()
.filter((e) -> {
System.out.println("迭代操作"); //短路
return e.getAge() > 24;
})
.limit(2)
.forEach(System.out :: println);
}
//跳过skip,distinct去重(要重写equals和hashcode)
@Test
public void test4(){
persons.stream()
.filter((e) -> e.getAge() > 23)
.skip(2)
.distinct()
.forEach(System.out :: println);
}
//映射
@Test
public void test5(){
List<String> list = Arrays.asList("a","bb","c","d","e");
list.stream().map((str) -> str.toUpperCase())
.forEach(System.out :: println);
System.out.println("---------------");
persons.stream().map((Person :: getName)).forEach(System.out :: println);
System.out.println("---------------");
Stream<Stream<Character>> stream = list.stream()
.map(TestSteamAPI2 :: filterCharacter);
stream.forEach((s) -> {
s.forEach(System.out :: println);
});
System.out.println("-----------------");
//flatMap
Stream<Character> stream2 = list.stream()
.flatMap(TestSteamAPI2 :: filterCharacter);
stream2.forEach(System.out :: println);
}
//处理字符串
public static Stream<Character> filterCharacter(String str){
List<Character> list = new ArrayList<>();
for (Character character : str.toCharArray()) {
list.add(character);
}
return list.stream();
}
//排序
@Test
public void test6(){
List<String> list = Arrays.asList("bb","c","aa","ee","ddd");
list.stream()
.sorted() //自然排序
.forEach(System.out :: println);
System.out.println("------------");
persons.stream()
.sorted((p1,p2) -> {
if (p1.getAge() == p2.getAge()) {
return p1.getName().compareTo(p2.getName());
} else {
return p1.getAge() - p2.getAge();
}
}).forEach(System.out :: println);
}
}
终止操作
查找与匹配方法
- allMatch(Perticate p) — 检查是否匹配所有元素
- anyMatch(Perticate p) — 检查是否至少匹配一个元素
- noneMatch(Perticate p) — 检查是否没有匹配的元素
- findFirst() — 返回第一个元素
- findAny() — 返回当前流中的任意元素
- count() — 返回流中元素的总个数
- max(Comparator c) — 返回流中最大值
- min(Comparator c) — 返回流中最小值
- forEach(Consumer c) — 内部迭代(使用Collection接口需用户做迭代成为外部迭代)
归约方法
- reduce(T identity, BinaryOperator b) — 可以将流中元素反复结合起来,得到一个值返回T
- reduce(BinaryOperator b) — 可以将流中元素反复结合起来,得到一个值,返回Optional
收集方法
collect(Collector c)——将流转换为其他形式,接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
/**
* Stream API的终止操作
*/
public class TestSteamAPI3 {
List<Person> persons = Arrays.asList(
new Person(2, "钱四", 24,Status.YOUNG),
new Person(1, "张三", 23,Status.YOUNG),
new Person(2, "李四", 24,Status.YOUNG),
new Person(3, "王五", 65,Status.OLD),
new Person(4, "赵六", 26,Status.MIDDLE),
new Person(4, "赵六", 56,Status.OLD),
new Person(5, "陈七", 27,Status.MIDDLE)
);
//查找与匹配
@Test
public void test1(){
boolean b = persons.stream()
.allMatch((e) -> e.getStatus().equals(Status.YOUNG));
System.out.println(b);
boolean b2 = persons.stream()
.anyMatch((e) -> e.getStatus().equals(Status.YOUNG));
System.out.println(b2);
boolean b3 = persons.stream()
.noneMatch((e) -> e.getStatus().equals(Status.MIDDLE));
System.out.println(b3);
Optional<Person> op = persons.stream()
.sorted((e1,e2) -> Integer.compare(e1.getAge(), e2.getAge()))
.findFirst();
System.out.println(op.get());
Optional<Person> optional = persons.stream()
.filter((e) -> e.getStatus().equals(Status.OLD))
.findAny();
System.out.println(optional.get());
}
//最大,最小
@Test
public void test2(){
long count = persons.stream()
.count();
System.out.println(count);
Optional<Person> optional = persons.stream()
.max((e1,e2) -> Integer.compare(e1.getId(), e2.getId()));
System.out.println(optional.get());
Optional<Integer> op = persons.stream()
.map(Person :: getAge)
.min(Integer :: compare);
System.out.println(op.get());
}
//归约
@Test
public void test3(){
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8);
Integer sum = list.stream()
.reduce(0, (x,y) -> x + y);
System.out.println(sum);
System.out.println("------------");
Optional<Integer> optional = persons.stream()
.map(Person :: getAge)
.reduce(Integer :: sum);
System.out.println(optional.get());
}
//收集
@Test
public void test4(){
List<String> list = persons.stream()
.map(Person :: getName)
.collect(Collectors.toList());
list.forEach(System.out :: println);
System.out.println("------------");
Set<String> set = persons.stream()
.map(Person :: getName)
.collect(Collectors.toSet());
set.forEach(System.out :: println);
System.out.println("------------");
HashSet<String> hashSet = persons.stream()
.map(Person :: getName)
.collect(Collectors.toCollection(HashSet :: new));
hashSet.forEach(System.out :: println);
}
@Test
public void test5(){
Long count = persons.stream()
.collect(Collectors.counting());
System.out.println("总人数="+count);
System.out.println("----------------");
//平均值
Double avg = persons.stream()
.collect(Collectors.averagingInt(Person :: getAge));
System.out.println("平均年龄="+avg);
System.out.println("---------------");
//总和
Integer sum = persons.stream()
.collect(Collectors.summingInt(Person :: getAge));
System.out.println("年龄总和="+sum);
System.out.println("----------------");
//最大值
Optional<Person> max = persons.stream()
.collect(Collectors.maxBy((e1,e2) -> Integer.compare(e1.getAge(), e2.getAge())));
System.out.println("最大年龄是"+max.get());
System.out.println("----------------");
//最小值
Optional<Person> min = persons.stream()
.collect(Collectors.minBy((e1,e2) -> Integer.compare(e1.getAge(), e2.getAge())));
System.out.println("最小年龄是"+min.get());
}
//分组
@Test
public void test6(){
Map<Status, List<Person>> map = persons.stream()
.collect(Collectors.groupingBy(Person :: getStatus));//根据年龄层分组
System.out.println(map);
}
//多级分组
@Test
public void test7(){
Map<Status, Map<String, List<Person>>> map = persons.stream()
.collect(Collectors.groupingBy(Person :: getStatus ,Collectors.groupingBy((e) -> {
if (e.getId()%2 == 1) {
return "单号";
} else {
return "双号";
}
})));
System.out.println(map);
}
//分区
@Test
public void test8(){
Map<Boolean, List<Person>> map = persons.stream()
.collect(Collectors.partitioningBy((e) -> e.getAge() > 30));
System.out.println(map);
}
//IntSummaryStatistics
@Test
public void test9(){
IntSummaryStatistics iss = persons.stream()
.collect(Collectors.summarizingInt(Person :: getAge));
System.out.println(iss.getSum());
System.out.println(iss.getAverage());
System.out.println(iss.getMax());
}
@Test
public void test10(){
String str = persons.stream()
.map(Person :: getName)
.collect(Collectors.joining(",","人员名单:","等"));
System.out.println(str);
}
}
并行流与串行
为了适应目前多核机器的时代,提高系统CPU、内存的利用率,在jdk1.8新的stream包中针对集合的操作也提供了并行操作流和串行操作流。并行流就是把内容切割成多个数据块,并且使用多个线程分别处理每个数据块的内容。Stream api中声明可以通过parallel()与sequential()方法在并行流和串行流之间进行切换,jdk1.8并行流使用的是fork/join框架进行并行操作
注:使用并行流并不是一定会提高效率,因为jvm对数据进行切片和切换线程也是需要时间的。所以数据量越小,串行操作越快;数据量越大,并行操作效果越好
/* FrokJoin框架
*/
public class ForkJoinCalculate extends RecursiveTask<Long>{
private static final long serialVersionUID = 1L;
private long start;
private long end;
private static final long THRESHOLD = 10000;
public ForkJoinCalculate() {
}
public ForkJoinCalculate(long start, long end) {
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
long length = end - start ;
if (length <= THRESHOLD) {
long sum = 0;
for (long i = start; i <= end; i++) {
sum += i;
}
return sum;
}else {
long middle = (start + end) / 2;
ForkJoinCalculate left = new ForkJoinCalculate();
left.fork();//拆分子任务,同时压入线程队列
ForkJoinCalculate right = new ForkJoinCalculate();
right.fork();
return left.join() + right.join();
}
}
}
public class TestForkJoin {
/**
* FrokJoin框架
*/
@Test
public void test1(){
Instant start = Instant.now();
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<Long> task = new ForkJoinCalculate(0,10000000000L);
Long sum = pool.invoke(task);
System.out.println(sum);
Instant end = Instant.now();
System.out.println(Duration.between(start,end).toMillis());
}
/**
* for循环
*/
@Test
public void test2(){
Instant start = Instant.now();
long sum = 0L;
for (long i = 0; i <= 10000000000L; i++) {
sum += i;
}
System.out.println(sum);
Instant end = Instant.now();
System.out.println(Duration.between(start, end).toMillis());
}
/**
* Java8并行流
*/
@Test
public void test3(){
Instant start = Instant.now();
LongStream.rangeClosed(0, 10000000000L)
.parallel()
.reduce(0,Long :: sum);
Instant end = Instant.now();
System.out.println(Duration.between(start, end).toMillis());
}
}
接口中的默认方法与静态方法
//jdk1.8以前接口中的变量必须是public static final的,方法也必须是public的,所以下面的定义是等价的
public interface MyService {
public static final String KEY = "hello world";
String key = "hello world";
public abstract void sayHello();
void sayHi();
}
//但是从jdk1.8开始,这种现象有了改变,jdk添加了接口的默认方法和静态方法,使用如下方式定义
public interface MyService {
/* 静态方法 */
static void method1(){
System.out.println("这个是静态方法,调用方式为:MyService.method1()");
}
/* 默认方法 */
default void method2(){
System.out.println("这个是默认方法,调用方式为MyService实例.method2()");
}
}
注:由于Java支持一个实现类可以实现多个接口,如果多个接口中存在同样的static和default方法会怎么样呢?
如果有两个接口中的静态方法一模一样,并且一个实现类同时实现了这两个接口,此时并不会产生错误,因为jdk8只能通过接口类调用接口中的静态方法,所以对编译器来说是可以区分的。但是如果两个接口中定义了一模一样的默认方法,并且一个实现类同时实现了这两个接口,那么必须在实现类中重写默认方法,否则编译失败
新时间日期API
原有日期api的缺点
- 从jdk1.1开始创建,日期处理没有规范,处于多个包中比如:java.util.Date,java.text.java.text.DateFormat等
- 现有的日期api存在多线程的线程安全问题(可通过比如ThreadLocal等方式规避)
新日期api简介
优势新日期api是线程安全的,统一放在java.time及其子包中,关注点分离,对于机器使用的时间戳和人可读的日期进行了类的分类
java.time及其子包说明
- java.time包:这是新的Java日期/时间API的基础包,所有的主要基础类都是这个包的一部分,如:LocalDate, LocalTime, LocalDateTime, Instant, Period, Duration等等。所有这些类都是不可变的和线程安全的,在绝大多数情况下,这些类能够有效地处理一些公共的需求
- java.time.chrono包:这个包为非ISO的日历系统定义了一些泛化的API,我们可以扩展AbstractChronology类来创建自己的日历系统
- java.time.format包:这个包包含能够格式化和解析日期时间对象的类,在绝大多数情况下,我们不应该直接使用它们,因为java.time包中相应的类已经提供了格式化和解析的方法
- java.time.temporal包:这个包包含一些时态对象,我们可以用其找出关于日期/时间对象的某个特定日期或时间,比如说,可以找到某月的第一天或最后一天。你可以非常容易地认出这些方法,因为它们都具有“withXXX”的格式
- java.time.zone包:这个包包含支持不同时区以及相关规则的类
public class LocalDateTimeTest {
/* localDate/localtime/localdateTime */
@Test
public void test1(){
//获取当前日期时间
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt);
//按照指定时间生成日期
LocalDateTime ldt1 = LocalDateTime.of(2020,12,30,1,2,3);
System.out.println(ldt1);
//指定时间+2年
System.out.println(ldt.plusYears(2));
//指定时间-3月
LocalDateTime ldt2 = ldt.minusMonths(3);
System.out.println(ldt2);
System.out.println(ldt.getYear());//获取年份
System.out.println(LocalDate.now());//获取日期
}
/* 时间戳 (使用Unix元年 1970年1月1日 00:00:00到现在的毫秒数 ) */
@Test
public void test2(){
Instant ins = Instant.now(); //默认使用UTC时区
System.out.println(ins+",,,"+ins.getEpochSecond());
OffsetDateTime odt = ins.atOffset(ZoneOffset.ofHours(8));//中国在东八区
System.out.println(odt);
Instant ins1 = Instant.ofEpochSecond(5);
System.out.println(ins1); //1970-01-01T00:00:05Z 从Unix元年偏移5s
}
/**
* Duration : 用于计算两个“时间”间隔
* Period : 用于计算两个“日期”间隔
* */
@Test
public void test3() throws InterruptedException {
Instant ins1 = Instant.now();
Thread.sleep(1000);
Instant ins2 = Instant.now();
System.out.println("两个时间的间隔为--》"+Duration.between(ins1,ins2)); //两个时间的间隔为--》PT1S
LocalDate date1 = LocalDate.of(2011,3,5);
LocalDate date2 = LocalDate.now();
Period pe = Period.between(date1,date2);
System.out.println("两个日期的间隔为--》"+ pe+",,间隔的年为--》"+pe.getYears()); //两个日期的间隔为--》P6Y18D,,间隔的年为--》6
}
/* 时间校正器 TemporalAdjuster */
@Test
public void test4(){
LocalDateTime ldt = LocalDateTime.now();
System.out.println("今天几号--> "+ldt.getDayOfMonth()); //今天几号--> 23
System.out.println("下个星期天是几号--》"+ ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY))); //下个星期天是几号--》2017-03-26T18:36:30.477
// 自定义下一个工作日
LocalDateTime dateTime = ldt.with((temporal)->{
LocalDateTime lt = (LocalDateTime)temporal;
DayOfWeek dow = lt.getDayOfWeek();
if(DayOfWeek.FRIDAY.equals(dow)){
return lt.plusDays(3);
}else if(DayOfWeek.SATURDAY.equals(dow)){
return lt.plusDays(2);
}else{
return lt.plusDays(1);
}
});
System.out.println("下个工作日是--》"+dateTime); //下个工作日是--》2017-03-24T22:42:31.789
}
/* 格式化日期 */
@Test
public void test5(){
// 自定义格式,当然也可以使用默认指定的格式
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime ldt = LocalDateTime.now();
System.out.println(format.format(ldt)); //2017-03-23 22:49:37
//字符串转日期
LocalDateTime ldt2 = LocalDateTime.parse("2017-11-12 23:10:05",format);
System.out.println(ldt2); //2017-11-12T23:10:05
}
/* 带时区的日期 ZonedDate、ZonedTime、ZonedDateTime */
@Test
public void test6(){
LocalDateTime ldt1 = LocalDateTime.now(ZoneId.of("Asia/Shanghai")); //Asia/shanghai time ->2017-03-23T22:57:21.084
System.out.println("Asia/shanghai time ->"+ldt1);
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("America/Marigot"));
System.out.println(zdt); //2017-03-23T10:59:43.708-04:00[America/Marigot]
System.out.println(zdt.toLocalDateTime());//2017-03-23T11:00:49.177 转换为当前时区时间
System.out.println("------------------------------------------------");
//获取时区ID列表
//ZoneId.getAvailableZoneIds().stream().forEach(System.out::println);
}
}
Optional
最大化减少空指针异常,Java 8引入了一个新的Optional类
Optional类是一个容器类,它可以保存类型T的值,代表这个值存在,或者保存为null,代表这个值不存在,
这是一个可以为null的容器对象,如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象
创造Optional类对象的API
-
Optional.of(T t):
-
为非null的值创建一个Optional实例,t不能为空
//调用工厂方法创建Optional实例
Optional<String> name = Optional.of("tom");
//传入参数为null,抛出NullPointerException.
Optional<String> someNull = Optional.of(null);
Optional.ofNullable(T t):较常用
- 创建一个Optional实例,t可为空
//下面创建了一个不包含任何值的Optional实例
Optional empty = Optional.ofNullable(null);
Optional.empty():
- 创建一个空的Optional实例
判断Optional容器是否包含对象
-
boolean isPresent():
-
非常容易理解,如果值存在返回true,否则返回false
void ifPresent(Consumer<? super T> ):
- 如果有值就执行Consumer接口的实现代码,并且该值会作为参数传给它
//ifPresent方法接受lambda表达式作为参数。
//lambda表达式对Optional的值调用consumer进行处理。
name.ifPresent((value) -> {
System.out.println("The length of the value is: " + value.length());
});
T orElse(T other):较常用
- 如果有值则将其返回,否则返回指定的其它值
T orElseGet(Suppliper<? entend X> other):
- 如果有值则将其返回,否则返回由Supplier接口实现提供的对象
//orElseGet与orElse方法类似,区别在于orElse传入的是默认值,
//orElseGet可以接受一个lambda表达式生成默认值。
System.out.println(empty.orElseGet(() -> "Default Value"));
System.out.println(name.orElseGet(() -> "Default Value"));
T orElseThrow(Suppliper<? entend X> exceptionSuppliper):
- 如果有值则将其返回,否则抛出由Supplier接口实现提供的异常
try {
//orElseThrow与orElse方法类似。与返回默认值不同,
//orElseThrow会抛出lambda表达式或方法生成的异常
empty.orElseThrow(ValueAbsentException::new);
} catch (Throwable ex) {
//输出: No value present in the Optional instance
System.out.println(ex.getMessage());
}
总结
篇幅有限!篇幅有限!关于Java8新特性,就聊到这儿啦..啦..啦..