Java1.8新特性
java1.8引入了许多的特性,在此我们主要讨论一下几点:
-
接口静态方法
-
接口默认方法 : 默认方法就是一个在接口里面有了一个或多个实现的方法。
-
函数式接口: 一个在接口只有一个待实现的方法。 (重要)
-
Lambda 表达式: Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。 (重要)
-
Stream API: 新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。 (重要)
-
Date Time API: 加强对日期与时间的处理。
-
Optional 类 − Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
接口静态方法
为什么接口要支持静态方法
接口中的静态方法背后的思想是提供一种简单的机制,允许通过将相关的方法内聚在接口中,而不必创建新的对象。
抽象类也可以做同样的事情。主要的区别在于抽象类可以有构造函数、成员变量和方法。
推荐把和只和接口相关的静态utility方法放在接口中(提高内聚性),而不需要额外创建一些utility类专门去放置这些方法。
interface NewInterface {
// 静态方法
static void hello()
{
System.out.println("Hello, New Static Method Here");
}
// 抽象方法
void overrideMethod(String str);
}
接口默认方法
Java 8 新增了接口的默认方法。
简单说,默认方法就是接口可以有实现方法,而且不需要实现类去实现其方法。
我们只需在方法名前面加个 default 关键字即可实现默认方法。
为什么要有这个特性?
首先,之前的接口是个双刃剑,好处是面向抽象而不是面向具体编程,缺陷是,当需要修改接口时候,需要修改全部实现该接口的类,目前的 java 8 之前的集合框架没有 foreach 方法,通常能想到的解决办法是在JDK里给相关的接口添加新的方法及实现。然而,对于已经发布的版本,是没法在给接口添加新方法的同时不影响已有的实现。所以引进的默认方法。他们的目的是为了解决接口的修改与现有的实现不兼容的问题。
JDK8 中接口默认方法有什么用
以前创建了一个接口,并且已经被大量的类实现。
如果需要再扩充这个接口的功能加新的方法,就会导致所有已经实现的子类需要重写这个方法。
如果在接口中使用默认方法就不会有这个问题。
所以从 JDK8 开始新加了接口默认方法,便于接口的扩展。
例子:
public interface Vehicle {
default void print(){
System.out.println("我是一辆车!");
}
}
函数式接口与Lambda表达式
为什么我要把这两个放一起讲呢?是因为Lambda表达式的原理就是调用的函数式接口
函数式接口与Lambda的关联
我以Runnable举例,这是一个最常见的函数式接口:
// 函数式接口的注解 @FunctionalInterface 其实也可以不加,而加上的理由:1、为了美观、易读 2、加上该注解能够更好地让编译器进行检查。
@FunctionalInterface
// 这个接口里面只有一个实现方法,被我们成为函数式接口
public interface Runnable {
public abstract void run();
}
作用:可以使用Lambda来简化函数式接口
public static void main(String[] args) {
// 就用Runable实现run的方法,启动线程
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("这个代码看着就很麻烦");
}
}).start();
// Lambda 表达式 是用来简化函数式接口的
new Thread(()->{
System.out.println("这个看着就很清爽");
}).start();
}
好,经过以上的两个案例,想必大家多少理解了函数式接口与Lambda是个啥玩意,那么下面我来说一下四大函数式接口,这里很重要,与Stream流息息相关
四大函数式接口
1、Function <T,R>:函数式接口,有参有返回值
我们先来看源码:安装1、2、3、的顺序读
@FunctionalInterface
// 1、相信大家看了也摸不着头脑 这样
public interface Function<T, R> {
// 3、我们就看这里,这里不就是说,给一个T的类,返回一个R的类吗?T与R是泛型,代指类
R apply(T t);
// 2、下面的这些有default关键字,是接口默认方法,所以我们就不看了,最后一个是接口静态方法,不是我们要找的函数式接口方法
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
好,上一步不理解没关系,这里我们看案例:
public static void main(String[] args) {
// 这里就是通过function方法把String的值转换为Integer类型,看着就很多
Function<String, Integer> function = new Function<String, Integer>() {
@Override
public Integer apply(String o) {
return Integer.parseInt(o);
}
};
System.out.println(function.apply("21"));
// 因为这是一个函数式接口,我们用Lambda简化一下
Function<String, Integer> function2 = (str)->{return Integer.parseInt(str);};
System.out.println(function2.apply("35"));
// 再简化,这里主要讲的函数式接口的使用,函数式接口与Lambda的关系,之后会将Lambda表达式的
Function<String, Integer> function3 = Integer::parseInt;
System.out.println(function3.apply("67"));
}
看一下输出:
2、Predicate < T >: 断言型接口,有参有返回值,返回值是boolean类型
我们先来看源码:
@FunctionalInterface
public interface Predicate<T> {
// 还是只看这个,意思就很明确了,传入一个泛型然后返回一个boolean类型
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
好,看案例:
Predicate<Integer> predicate = new Predicate<Integer>() {
@Override
public boolean test(Integer o) {
if (o>10){
return true;
}else {
return false;
}
}
};
System.out.println("predicate--1==>"+predicate.test(1));
System.out.println("predicate--11==>"+predicate.test(11));
//因为这是一个函数式接口,我们用Lambda简化一下
Predicate<Integer> predicate2 = (o)->{
if (o>10){
return true;
}else {
return false;
}
};
System.out.println("predicate2--15==>"+predicate2.test(15));
看结果:
3、Consumer < T >:消费型接口,有参无返回值
看源码:
@FunctionalInterface
public interface Consumer<T> {
// 还是看这个 不就是说放一个值进来 没有返回值嘛
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
看案例:
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String o) {
System.out.println("胖虎打"+o);
}
};
consumer.accept("大熊");
// Lambda简化
Consumer<String> consumer2 = str ->{
System.out.println("大熊打"+str);
};
consumer2.accept("胖虎");
结果:
4、Supplier < T >:供给型接口,无参有返回值
看源码:
@FunctionalInterface
public interface Supplier<T> {
// 没有传参返回一个 T 类型的值
T get();
}
看案例:
Supplier<String> supplier = new Supplier<String>() {
@Override
public String get() {
return "就没有返回值";
}
};
System.out.println(supplier.get());
//简化
Supplier<Integer> supplier2 = ()->{ return 1024; };
System.out.println(supplier2.get());
结果:
Lambda表达式:
Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。
Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
使用 Lambda 表达式可以使代码变的更加简洁紧凑。
语法
lambda 表达式的语法格式如下:
(parameters) -> expression
或
(parameters) ->{ statements; }
lambda表达式的重要特征:
- **可选类型声明:**不需要声明参数类型,编译器可以统一识别参数值。
- **可选的参数圆括号:**一个参数无需定义圆括号,但多个参数需要定义圆括号。
- **可选的大括号:**如果主体包含了一个语句,就不需要使用大括号。
- **可选的返回关键字:**如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定表达式返回了一个数值。
Lambda 表达式简单实例
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
案例:
public class Java8Tester {
public static void main(String args[]){
Java8Tester tester = new Java8Tester();
// 类型声明
MathOperation addition = (int a, int b) -> a + b;
// 不用类型声明
MathOperation subtraction = (a, b) -> a - b;
// 大括号中的返回语句
MathOperation multiplication = (int a, int b) -> { return a * b; };
// 没有大括号及返回语句
MathOperation division = (int a, int b) -> a / b;
System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
System.out.println("10 / 5 = " + tester.operate(10, 5, division));
// 不用括号
GreetingService greetService1 = message ->
System.out.println("Hello " + message);
// 用括号
GreetingService greetService2 = (message) ->
System.out.println("Hello " + message);
greetService1.sayMessage("Runoob");
greetService2.sayMessage("Google");
}
// 这也是函数式接口 只不过是类里面的接口
interface MathOperation {
int operation(int a, int b);
}
interface GreetingService {
void sayMessage(String message);
}
private int operate(int a, int b, MathOperation mathOperation){
return mathOperation.operation(a, b);
}
}
输出结果:
10 + 5 = 15
10 – 5 = 5
10 x 5 = 50
10 / 5 = 2
Hello Runoob
Hello Google
这里我就带大家过一遍,Lambda知识点很多,入门或者正常使用的话,看我这个就足够了,如果还行深究就可以看一下这篇文章:Java-lambda表达式入门看这一篇就够了 – 腾讯云开发者社区-腾讯云 (tencent.com)
Stream流:
Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
什么是 Stream?
Stream(流)是一个来自数据源的元素队列并支持聚合操作
- 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
- 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
- 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
和以前的Collection操作不同, Stream操作还有两个基础的特征:
- Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
- 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。
按照装我的理解,这玩意就是用来处理集合的,而且非常的高效
生成流
在 Java 8 中, 集合接口有两个方法来生成流:
- stream() − 为集合创建串行流。
- parallelStream() − 为集合创建并行流。
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
各种API:
forEach
Stream 提供了新的方法 ‘forEach’ 来迭代流中的每个数据。以下代码片段使用 forEach 输出了10个随机数:
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
map
map 方法用于映射每个元素到对应的结果,以下代码片段使用 map 输出了元素对应的平方数:
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
// 获取对应的平方数
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
filter
filter 方法用于通过设置的条件过滤出元素。以下代码片段使用 filter 方法过滤出空字符串:
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 获取空字符串的数量
long count = strings.stream().filter(string -> string.isEmpty()).count();
limit
limit 方法用于获取指定数量的流。 以下代码片段使用 limit 方法打印出 10 条数据:
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
sorted
sorted 方法用于对流进行排序。以下代码片段使用 sorted 方法对输出的 10 个随机数进行排序:
Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);
并行(parallel)程序
parallelStream 是流并行处理程序的代替方法。以下实例我们使用 parallelStream 来输出空字符串的数量:
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 获取空字符串的数量
long count = strings.parallelStream().filter(string -> string.isEmpty()).count();
我们可以很容易的在顺序运行和并行直接切换。
Collectors
Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串:
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
System.out.println("筛选列表: " + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("合并字符串: " + mergedString);
统计
另外,一些产生统计结果的收集器也非常有用。它们主要用于int、double、long等基本类型上,它们可以用来产生类似如下的统计结果。
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();
System.out.println("列表中最大的数 : " + stats.getMax());
System.out.println("列表中最小的数 : " + stats.getMin());
System.out.println("所有数之和 : " + stats.getSum());
System.out.println("平均数 : " + stats.getAverage());
我的案例:
public class Demo {
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
Student student = new Student(18,"张三",1);
list.add(student);
student = new Student(13,"张三",1);
list.add(student);
student = new Student(21,"李四",1);
list.add(student);
student = new Student(10,"小红",0);
list.add(student);
student = new Student(25,"大红",0);
list.add(student);
// 我在里面list存放了 四个对象
// 1、18岁男性张三
// 2、21岁男性李四
// 3、10岁女性小红
// 4、25岁女性大红
// 案例一、现在我要找所有的女性
System.out.println("案例一、现在我要找所有的女性");
List<Student> collect = list.stream().filter(x -> {
return x.getSex() == 0;
}).collect(Collectors.toList());
for (Student student1 : collect) {
System.out.println(student1);
}
System.out.println("简化案例一");
// 案例一、简化
list.stream().filter(x->{return x.getSex()==0;}).collect(Collectors.toList()).forEach(System.out::println);
// 案例二、所有人名字
System.out.println("案例二、所有人名字");
list.stream().map(Student::getName).collect(Collectors.toList()).forEach(x->{
System.out.print(x+"、");
});
System.out.println();
System.out.println("案例二、所有人名字且不重复");
list.stream().map(Student::getName).collect(Collectors.toSet()).forEach(x->{
System.out.print(x+"、");
});
System.out.println();
System.out.println("案例三、所有人名字且只要三条条数据");
list.stream().map(Student::getName).limit(3).collect(Collectors.toList()).forEach(x->{
System.out.print(x+"、");
});
}
}
class Student{
private int age;
private String name;
private int sex; // 0为女 1为男
public Student(int age, String name, int sex) {
this.age = age;
this.name = name;
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
", sex=" + sex +
'}';
}
}
这里我就带大家过一遍,Stream知识点很多,入门或者正常使用的话,看我这个就足够了,如果还行深究就可以看一下这篇文章:Java8 Stream:2万字20个实例,玩转集合的筛选、归约、分组、聚合_云深i不知处的博客-CSDN博客_java stream 分组聚合
日期时间 API
Java 8通过发布新的Date-Time API (JSR 310)来进一步加强对日期与时间的处理。
在旧版的 Java 中,日期时间 API 存在诸多问题,其中有:
- 非线程安全 − java.util.Date 是非线程安全的,所有的日期类都是可变的,这是Java日期类最大的问题之一。
- 设计很差 − Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。
- 时区处理麻烦 − 日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有的问题。
Java 8 在 java.time 包下提供了很多新的 API。以下为两个比较重要的 API:
- Local(本地) − 简化了日期时间的处理,没有时区的问题。
- Zoned(时区) − 通过制定的时区处理日期时间。
新的java.time包涵盖了所有处理日期,时间,日期/时间,时区,时刻(instants),过程(during)与时钟(clock)的操作。
本地化日期时间 API
LocalDate/LocalTime 和 LocalDateTime 类可以在处理时区不是必须的情况。代码如下:
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;
import java.time.Month;
public class Java8Tester {
public static void main(String args[]){
Java8Tester java8tester = new Java8Tester();
java8tester.testLocalDateTime();
}
public void testLocalDateTime(){
// 获取当前的日期时间
LocalDateTime currentTime = LocalDateTime.now();
System.out.println("当前时间: " + currentTime);
LocalDate date1 = currentTime.toLocalDate();
System.out.println("date1: " + date1);
Month month = currentTime.getMonth();
int day = currentTime.getDayOfMonth();
int seconds = currentTime.getSecond();
System.out.println("月: " + month +", 日: " + day +", 秒: " + seconds);
LocalDateTime date2 = currentTime.withDayOfMonth(10).withYear(2012);
System.out.println("date2: " + date2);
// 12 december 2014
LocalDate date3 = LocalDate.of(2014, Month.DECEMBER, 12);
System.out.println("date3: " + date3);
// 22 小时 15 分钟
LocalTime date4 = LocalTime.of(22, 15);
System.out.println("date4: " + date4);
// 解析字符串
LocalTime date5 = LocalTime.parse("20:15:30");
System.out.println("date5: " + date5);
}
}
输出结果:
当前时间: 2016-04-15T16:55:48.668
date1: 2016-04-15
月: APRIL, 日: 15, 秒: 48
date2: 2012-04-10T16:55:48.668
date3: 2014-12-12
date4: 22:15
date5: 20:15:30
使用时区的日期时间API
如果我们需要考虑到时区,就可以使用时区的日期时间API:
import java.time.ZonedDateTime;
import java.time.ZoneId;
public class Java8Tester {
public static void main(String args[]){
Java8Tester java8tester = new Java8Tester();
java8tester.testZonedDateTime();
}
public void testZonedDateTime(){
// 获取当前时间日期
ZonedDateTime date1 = ZonedDateTime.parse("2015-12-03T10:15:30+05:30[Asia/Shanghai]");
System.out.println("date1: " + date1);
ZoneId id = ZoneId.of("Europe/Paris");
System.out.println("ZoneId: " + id);
ZoneId currentZone = ZoneId.systemDefault();
System.out.println("当期时区: " + currentZone);
}
}
输出结果为:
date1: 2015-12-03T10:15:30+08:00[Asia/Shanghai]
ZoneId: Europe/Paris
当期时区: Asia/Shanghai
Optional 类
Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
Optional 类的引入很好的解决空指针异常。
类声明
以下是一个 java.util.Optional 类的声明:
public final class Optional<T>
extends Object
类方法
序号 | 方法 & 描述 |
---|---|
1 | **static Optional empty()**返回空的 Optional 实例。 |
2 | **boolean equals(Object obj)**判断其他对象是否等于 Optional。 |
3 | **Optional filter(Predicate<? super predicate)**如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional。 |
4 | ** Optional flatMap(Function<? super T,Optional> mapper)**如果值存在,返回基于Optional包含的映射方法的值,否则返回一个空的Optional |
5 | **T get()**如果在这个Optional中包含这个值,返回值,否则抛出异常:NoSuchElementException |
6 | **int hashCode()**返回存在值的哈希码,如果值不存在 返回 0。 |
7 | **void ifPresent(Consumer<? super T> consumer)**如果值存在则使用该值调用 consumer , 否则不做任何事情。 |
8 | **boolean isPresent()**如果值存在则方法会返回true,否则返回 false。 |
9 | **Optional map(Function<? super T,? extends U> mapper)**如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional。 |
10 | **static Optional of(T value)**返回一个指定非null值的Optional。 |
11 | **static Optional ofNullable(T value)**如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional。 |
12 | **T orElse(T other)**如果存在该值,返回值, 否则返回 other。 |
13 | **T orElseGet(Supplier<? extends T> other)**如果存在该值,返回值, 否则触发 other,并返回 other 调用的结果。 |
14 | ** T orElseThrow(Supplier<? extends X> exceptionSupplier)**如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常 |
15 | **String toString()**返回一个Optional的非空字符串,用来调试 |
注意: 这些方法是从 java.lang.Object 类继承来的。
Optional 实例
我们可以通过以下实例来更好的了解 Optional 类的使用:
import java.util.Optional;
public class Java8Tester {
public static void main(String args[]){
Java8Tester java8Tester = new Java8Tester();
Integer value1 = null;
Integer value2 = new Integer(10);
// Optional.ofNullable - 允许传递为 null 参数
Optional<Integer> a = Optional.ofNullable(value1);
// Optional.of - 如果传递的参数是 null,抛出异常 NullPointerException
Optional<Integer> b = Optional.of(value2);
System.out.println(java8Tester.sum(a,b));
}
public Integer sum(Optional<Integer> a, Optional<Integer> b){
// Optional.isPresent - 判断值是否存在
System.out.println("第一个参数值存在: " + a.isPresent());
System.out.println("第二个参数值存在: " + b.isPresent());
// Optional.orElse - 如果值存在,返回它,否则返回默认值
Integer value1 = a.orElse(new Integer(0));
//Optional.get - 获取值,值需要存在
Integer value2 = b.get();
return value1 + value2;
}
}
输出结果为:
第一个参数值存在: false
第二个参数值存在: true
10
以上部分内容参照:
Java 8 日期时间 API | 菜鸟教程 (runoob.com)
Nullable(value1);
// Optional.of - 如果传递的参数是 null,抛出异常 NullPointerException
Optional<Integer> b = Optional.of(value2);
System.out.println(java8Tester.sum(a,b));
}
public Integer sum(Optional a, Optional b){
// Optional.isPresent - 判断值是否存在
System.out.println("第一个参数值存在: " + a.isPresent());
System.out.println("第二个参数值存在: " + b.isPresent());
// Optional.orElse - 如果值存在,返回它,否则返回默认值
Integer value1 = a.orElse(new Integer(0));
//Optional.get - 获取值,值需要存在
Integer value2 = b.get();
return value1 + value2;
}
}
输出结果为:
> 第一个参数值存在: false
> 第二个参数值存在: true
> 10
## 以上部分内容参照:
[Java 8 日期时间 API | 菜鸟教程 (runoob.com)](https://www.runoob.com/java/java8-datetime-api.html)
[Java 8 Optional 类 | 菜鸟教程 (runoob.com)](https://www.runoob.com/java/java8-optional-class.html)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/74724.html