JavaBase-Java8新特性
简介
- 速度更快
- 代码更少(增加了新的语法:Lambda表达式)
- 强大的Stream API
- 便于并行
- 最大化减少空指针异常:Optional
- Nashorn引擎,允许JVM上运行JS应用
并行流与串行流
- 并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。相比串行流,并行流可以很大程度上提高程序的执行效率
- Java8中将并行进行优化骂我们可以很容易的对数据进行并行操作。
- StreamAPI可以声明性地通过parallel()与sequential()在并行流与顺序流之间进行切换
Lambda表达式
-
Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。使它可以写出简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升
-
public static void main(String[] args) { Thread t1 = new Thread(() -> System.out.println("dfasfsd")); t1.start(); Comparator<Integer> c = Integer::compareTo; System.out.println(c.compare(1, 2)); }
Lambda表达式的使用
-
举例:(o1,o2) -> Integer.compareTo(o1,o2);
-
格式:
- ->:lambda表达式 或 箭头操作符
- ->左边:lambda形参列表(其实就是接口中的抽象方法中的形参列表)
- ->右边:lambda体(其实就是重写的抽象方法的方法体)
-
Lambda表达式的使用:(分6种情况)
-
语法格式一:无参,无返回值
-
Runnable runnable = () -> System.out.println("你好");
-
-
语法格式二:Lambda了需要一个参数,但是没有返回值
-
Consumer<String> con = (String str) -> System.out.println(str);
-
-
语法格式三:数据类型可以省略,因为可由编译期判断得出,称为“类型判断”
-
Consumer<String> con = (str) -> System.out.println(str);
-
-
语法格式四:Lambda若只需要一个参数,参数的小括号可以省略
-
Consumer<String> con = str -> System.out.println(str);
-
-
语法格式五:Lambda需要两个或以上的参数,多条执行语句,并且可以有返回值
-
Comparator<Integer> com = (x,y) -> { return Integer.compare(x,y) };
-
-
语法格式六:当Lambda体只有一条语句时,return与大括号若有,都可以省略
-
Comparator<Integer> com2 = (x,y) -> Integer.compare(x,y);;
-
-
-
Lambda表达式的本质:作为接口的实例
-
Lambda表达式总结:
- ->左边:Lambda形参列表的参数类型可以省略(类型判断);如果Lambda形参列表只有一个参数,其一对()可以省略
- ->右边:Lambda体应使用一对{}包裹;如果lambda体只有一条执行越剧(可能是return语句),可以省略一对{}和return关键字
函数式(Functional)接口
- 只包含一个抽象方法的接口,称为函数式接口
- 可以通过Lambda表达式来创建该接口的对象。(若Lambda表达式抛出一个受检异常(即:非运行异常),那么该异常需要在目标接口的抽象方法上进行声明)。
- 我们可以在一个接口上使用@FunctionalInterface注解,这样做可以检查它是否是一个函数式接口。同时javadoc也会包含一条声明,说明这个接口是一个函数式接口
Java内置四大核心函数式接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
Consumer消费型jiekou | T | void | 对类型为T的对象应用操作,包含方法,void accept(T t) |
Supplier供给型接口 | 无 | T | 返回类型为T的对象,包含方法:T get() |
Function<T,R>函数型接口 | T | R | 对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:R apply(T t) |
Predicate断定型接口 | T | boolean | 确定类型为T的对象是否满足某约束,并返回boolean值。包含方法:boolean test(T t) |
例子:
-
Consumer
-
Consumer<String> consumer = (t)-> System.out.println(t); consumer.accept("dfasdf");
-
-
Supplier
-
Supplier<String> supplier = () -> "dfasfdas"; System.out.println(supplier.get());
-
-
Function<T,R>
-
Function<String,Integer> function = (s)->{ System.out.println(s); return 1; }; System.out.println(function.apply("Dfadf"));
-
-
Predicate
-
Predicate<String> predicate = (x) -> x.compareTo("t") > -1; System.out.println(predicate.test("dasfd"));
-
方法引用与构造器引用
方法引用
-
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
-
方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖
-
要求:实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致。
-
格式:使用操作符“::”将类(或对象)与方法名分隔开来。
-
如下三种主要使用情况:
-
对象::实例方法名
-
/** * 情况1:对象 :: 实例方法 * Consumer中的 void accept(T t); * PrintStream中的 void println(T t); */ @Test public void test1(){ Consumer<String> consumer1 = str -> System.out.println(str); consumer1.accept("你好"); System.out.println("*************************"); Consumer<String> consumer2 = System.out :: println; consumer2.accept("你好2"); }
-
-
类::静态方法名
-
/** * 情况2: 类 :: 静态方法 * */@Testpublic void test2(){ Comparator<Integer> comparator1 = (t1,t2)->Integer.compare(t1,t2); comparator1.compare(1,2); System.out.println("***********************"); Comparator<Integer> comparator2 = Integer ::compare; comparator2.compare(1,2);}
-
-
类::实例方法名
-
/** * 情况三:类 :: 实例方法 * Comparator中的int compare(T t1,T t2) * String中的int t1.compareTo(t2) */ @Test public void test5(){ Comparator<String> comparator1 = (s1,s2) -> s1.compareTo(s2); Comparator<String> comparator = String :: compareTo; BiPredicate<String,String> biPredicate = (t1,t2) -> t1.equals(t2); System.out.println(biPredicate.test("A", "A")); System.out.println("************************"); BiPredicate<String,String> biPredicate1 = String :: equals; System.out.println(biPredicate1.test("B", "B")); }
-
-
-
使用情境:当腰传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
-
方法引用,本质上就是Lambda表达式,而Lambda表达式作为函数式接口的实例。所以方法引用,也是函数式接口的实例
-
//类 :: 静态方法名 Comparator<Integer> c = Integer::compareTo; System.out.println(c.compare(1, 2)); //对象 :: 实例方法名 Supplier<Integer> supplier = new Integer(1) :: intValue; //类 :: 实例方法名 Function<Integer, Integer> integerIntegerFunction = Integer::intValue;
构造器引用
-
和方法引用类似,函数接口的抽象方法和形参列表和构造器的形参列表一致
-
抽象方法的返回值类型即为构造器所属的类的类型
-
public class Employee { private int id; private String name; private int age; private Double salary; public Employee(int id) { this.id = id; } } /** * 构造器引用 */ @Test public void test6(){ Function<Integer, Employee> integerEmployeeFunction = Employee::new; System.out.println(integerEmployeeFunction.apply(1)); }
-
数组引用
可以把数组看作是一个特殊的类,则写法与构造器一样
/** * 数组引用 */@Testpublic void test7(){ Function<Integer,String[]> function = length -> new String[length]; System.out.println(function.apply(1)); System.out.println("*********************"); Function<Integer,String[]> function1 = String[] :: new; System.out.println(function1.apply(9));}
强大的StreamAPI
概念
- Java8中有两个最为重要的改变。第一个是Lambda表达式;另一个则是Stream API;
- Stream API(java.util.stream)把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充,因为Stream API可以极大提供Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
- Stream是Java8中处理集合的关键抽象概念,它可以指定希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Sream API对集合数据进行操作,就类似于使用SQL执行的数据库查询。也可以使用Stream API来并行执行操作。简而言之,Stream API提供了一种高效而易于使用的处理数据的方式
为什么要使用Stream API
- 实际开发中,项目中多数数据源都来自于MySql,Oracle等。但现在数据源可以更多了,有MongDB,Redis等,而这些NoSQL的数据就需要Java层面去处理。
- Collection集合和Stream的区别:Collection是一种静态的内存数据结构,而Stream是有关计算的。前者主要面向内存,存储在内存中,后者主要面向CPU,通过CPU实现计算。
什么是Stream API
- Stream到底是什么?
- 是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
- “集合讲的是数据,Stream讲的是计算“
- 注意
- Stream自己不会存储元素
- Stream不会改变源对象。相反,他们会返回一个持有结果的Stream。
- Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
Stream的操作三个步骤
- 1-创建Stream
- 一个数据源(如:集合、数组),获取一个流
- 2-中间操作
- 一个中间操作链,对数据源的数据进行处理
- 3-终止操作
- 一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用
创建Stream方式
-
创建Stream方式一:通过集合
-
Java8的Collection接口被扩展,提供了两个获取流的方法:
- default Stream stream(): 返回一个顺序流
- default Stream parallelStream():返回一个并行流
-
/** * 创建Stream方式一:通过集合 */ @Test public void test1(){ List<Employee> employees = EmployeeData.getEmployees(); //default Stream<E> stream():返回一个顺序流 Stream<Employee> stream = employees.stream(); //default Stream<E> parallelStream():返回一个并行流 Stream<Employee> employeeStream = employees.parallelStream(); }
-
-
创建Stream方式二:通过数组
-
Java8中Arrays的静态方法stream()可以获取数组流:
- static Stream stream(T[] arrays):返回一个流
- 重载形式,能够处理对应基本数据类型的数组:
- public static IntStream stream(int[] array)
- public static LongStream stream(long[] array)
- public static DoubleStream stream(double[] array)
-
/** * 创建Stream方式二:通过数组 */ @Test public void test2(){ int[] ints = new int[]{1,2,3}; IntStream stream = Arrays.stream(ints); Employee[] employees = new Employee[]{new Employee(1,"2",1,21.0)}; Stream<Employee> stream1 = Arrays.stream(employees); }
-
-
创建Stream方式三:通过Stream的of()
-
可以调用Stream类静态方法of(),通过显示值创建一个流。它可以接受任意数量的参数。
-
public static Stream of(T… values):返回一个流
-
/** * 创建Stream方式三:通过Stream的of() */ @Test public void test3(){ Stream<Integer> integerStream = Stream.of(1, 2, 3); }
-
-
-
创建Stream方式四:创建无限流
-
可以使用静态方法Stream.iterate()和Stream.generate(),创建无限流。
- 迭代
- public static Stream iterate(final T seed,final UnaryOperator f)
- 生成
- public static Stream generate(Supplier s)
- 迭代
-
/** * 创建Stream方式四:创建无限流 */ @Test public void test4(){ //迭代 //public static<T> Stream<T> iterate(final T seed,final UnaryOperator<T> f) Stream.iterate(new Employee(1,"dfsf",1,23.0), (t)->{ return new Employee(t.getId()+1); }).limit(10).forEach(System.out::println); //生成 //public static<T> Stream<T> generate(Supplier<T> s) Random random = new Random(); Stream.generate(()-> random.nextInt(10)).limit(10).forEach(System.out::println); }
-
Stream的中间操作
-
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”
-
1-筛选与切片
-
方法 描述 filter(Predicate p) 接收Lambda,从流中排除某些元素 distinct() 筛选,通过流所生成元素的hashCode()和equals去除重复元素 limit(long maxSize) 截断流,使其元素不超过给定数量 skip(long n) 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补 -
代码
-
@Test public void test6(){ //distinct() 筛选,通过流所生成元素的hashCode()和equals去除重复元素 EmployeeData.getEmployees().stream().distinct().forEach(System.out::println); } @Test public void test7(){ EmployeeData.getEmployees().stream().forEach(System.out::println); System.out.println("********************"); //limit(long maxSize) 截断流,使其元素不超过给定数量 EmployeeData.getEmployees().stream().limit(2).forEach(System.out::println); } @Test public void test8(){ EmployeeData.getEmployees().stream().forEach(System.out::println); System.out.println("********************"); //skip(long n) 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补 EmployeeData.getEmployees().stream().skip(2).forEach(System.out::println); }
-
-
-
2-映射
-
方法 描述 map(Function f) 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素 mapToDouble(ToDoubleFuncion f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的DoubleStream。 mapToInt(ToIntFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的IntStream。 mapToLong(ToLongFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的LongStream。 flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流 -
代码例子
-
@Test public void test1(){ //map(Function f) 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素 EmployeeData.getEmployees().stream().map((e)->{ e.setId(e.getId()+1000); return e; }).forEach(System.out::println); System.out.println("********************"); EmployeeData.getEmployees().stream() .filter((e)->e.getName().length()>3).map(Employee::getName).forEach(System.out::println); } @Test public void test2(){ //mapToDouble(ToDoubleFuncion f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的DoubleStream。 EmployeeData.getEmployees().stream().mapToDouble((e)->e.getSalary()).forEach(System.out::println); } @Test public void test3(){ //mapToInt(ToIntFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的IntStream。 EmployeeData.getEmployees().stream().mapToInt((e)->e.getId()).forEach(System.out::println); } @Test public void test4(){ //mapToLong(ToLongFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的LongStream。 EmployeeData.getEmployees().stream().mapToLong((e)->e.getAge()).forEach(System.out::println); } @Test public void test5(){ //flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流 EmployeeData.getEmployees().stream().forEach(System.out::println); System.out.println("*****************"); EmployeeData.getEmployees().stream().flatMap((e)-> Arrays.asList(e).stream()).forEach(System.out::println); } @Test public void test6(){ List<String> list = Arrays.asList("aa","BB","CC","DD"); Stream<Stream<Character>> streamStream = list.stream().map(StreamAPITest2::fromStringToStream); streamStream.forEach((i)->{ i.forEach(System.out::println); }); System.out.println("***********************"); Stream<Character> characterStream = list.stream().flatMap(StreamAPITest2::fromStringToStream); characterStream.forEach(System.out::println); } @Test public void test7(){ List<String> list = Arrays.asList("aa","BB","CC","DD"); Stream<ArrayList<Character>> arrayListStream = list.stream().map(StreamAPITest2::fromStringToStream2); arrayListStream.forEach(System.out::println); System.out.println("***********************"); Stream<Character> characterStream = list.stream().flatMap((s) -> StreamAPITest2.fromStringToStream2(s).stream()); characterStream.forEach(System.out::println); System.out.println("***********************"); Stream<Stream<Character>> streamStream = list.stream().map((s) -> StreamAPITest2.fromStringToStream2(s).stream()); streamStream.forEach(System.out::println); } private static Stream<Character> fromStringToStream(String str) { ArrayList<Character> list = new ArrayList<>(); for(Character c : str.toCharArray()){ list.add(c); } return list.stream(); } private static ArrayList<Character> fromStringToStream2(String str) { ArrayList<Character> list = new ArrayList<>(); for(Character c : str.toCharArray()){ list.add(c); } return list; }
-
-
-
3-排序
-
方法 描述 sorted() 产生一个新流,其中按自然顺序排序 sorted(Comparator com) 产生一个新流,其中按比较器定制排序顺序排序 -
代码
-
@Test public void test1(){ //sorted() 产生一个新流,其中按自然顺序排序 EmployeeData.getEmployees().stream().sorted().forEach(System.out::println); } @Test public void test2(){ //sorted(Comparator com) 产生一个新流,其中按比较器定制排序顺序排序 EmployeeData.getEmployees().stream().sorted((e1,e2)->{ return Integer.compare(e1.getAge(),e2.getAge()); }).forEach(System.out::println); System.out.println("***************"); EmployeeData.getEmployees().stream().sorted(Comparator.comparingInt(Employee::getAge)).forEach(System.out::println); }
-
-
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使用内部迭代—它帮忙把迭代做了
-
-
代码
-
@Test public void test1(){ // allMatch(Predicate p) 检查是否匹配所有元素 System.out.println(EmployeeData.getEmployees().stream().allMatch(employee -> employee.getSalary() > 2000)); } @Test public void test2(){ // anyMatch(Predicate p) 检查是否至少匹配一个元素 System.out.println(EmployeeData.getEmployees().stream().anyMatch(employee -> employee.getSalary() > 2000)); } @Test public void test3(){ // noneMatch(Predicate p) 检查是否没有匹配所有元素 System.out.println(EmployeeData.getEmployees().stream().noneMatch(employee -> employee.getSalary() < 0)); } @Test public void test4(){ // noneMatch(Predicate p) 检查是否没有匹配所有元素 System.out.println(EmployeeData.getEmployees().stream().findFirst()); } @Test public void test5(){ // findAny() 返回当前流中的任意元素 System.out.println(EmployeeData.getEmployees().stream().findAny()); } @Test public void test6(){ // count() 返回流中元素总数 System.out.println(EmployeeData.getEmployees().stream().count()); } @Test public void test7(){ // max(Comparator c) 返回流中最大值 //返回年龄最大的对象 如果出现两个对象,返回的是先被找到的对象 System.out.println(EmployeeData.getEmployees().stream() .max(Comparator.comparingInt(Employee::getAge))); } @Test public void test8(){ // max(Comparator c) 返回流中最大值 //返回年龄最小的对象 如果出现两个对象,返回的是先被找到的对象 System.out.println(EmployeeData.getEmployees().stream() .min(Comparator.comparingInt(Employee::getAge))); } @Test public void test9(){ // forEach(Consumer c) 内部迭代(使用Collection接口需要用户去做迭代,称为外部迭代。相反,Stream API使用内部迭代---它帮忙把迭代做了 EmployeeData.getEmployees().stream().forEach((e)->{ e.getSalary(); System.out.println(e.getSalary()+1); }); }
-
-
-
2-归约
-
备注:
- Map和reduce的连接通常称为map-reduce的连接通常称为map-reduce模式,因Google用它来进行网络搜索而名
-
方法 描述 reduce(T iden,BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回T reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回Optional -
代码例子
-
@Test public void test10(){ //reduce(T iden,BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回T //练习1 : 计算1-10的自然数的和 List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10); Integer reduce1 = list.stream().reduce(0, (t1, t2) -> { return t1 + t2; }); System.out.println(reduce1); //reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回Optional<T> //练习2:计算所有员工工资总和 OptionalDouble reduce = EmployeeData.getEmployees().stream() .mapToDouble(Employee::getSalary).reduce(Double::sum); System.out.println(reduce.getAsDouble()); }
-
-
-
3-收集
-
备注
-
Collector接口中方法的实现决定了如何对流执行收集的操作(如收集到List、Set、Map)。
-
另外,Collectors使用类提供了很多静态方法,可以方便地创建常见收集齐实例,
-
方法 返回类型 作用 toList List 把流中元素收集到List List list = list.stream().collect(Collectors.toList()); toSet Set 把流中元素收集到Set Set set = list.stream().collect(Collectors.toSet()); toCollection Collection 把流中的元素收集到创建的集合 Collection emps = list.stream().collect(Collectors.toCollection(ArrayList::new))l counting Long 计算流中元素的个数 long count = list.stream().collect(Collectors.counting()); summingInt Integer 对流中元素的整数属性求和 int total=list.stream().collect(Collectors.summingInt(Employee::getSalary)); averageingInt Double 计算流中元素Integer属性的平均值 double avg = list.stream().collect(Collectors.averagingInt(Employee::getSalary)); summrizingInt IntSummaryStatistics 收集流中Integer属性的统计值。如:平均值 int SummaryStatisticsiss = list.stream().collect(Collectors.summarizingInt(Employee::getSalary)); joining String 连接流中每个字符串 String str =list.stream().map(Employee::getName).collect(Collectors.joining)); maxBy Optional 根据比较器选择最大值 Optional max = list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary)); minBy Optional 根据比较器选择最小值 Optional min = list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary)); reducing 归约产生的类型 从一个作为累加器的初始值开始,利用BinaryOperator与流中元素逐个结合,从未归约成单个值 int total=list.stream().collect(Collectors.reducing(0,Employee::getSalary,Integer::sum)); collectingAndThen 转换函数返回的类型 包裹另一个收集齐,对其结果转换函数 int how = list.stream().collect(Collectors.collectingAndThen(Collectors.toList(),List::size) groupingBy Map<K,List> 根据某属性值对流分组,属性为K,结果为V Map<Emp.Status,List> map = list.stream().collect(Collectors.groupingBy(Employee::getStatus)); partitioningBy Map<Boolean,List> 根据true或false进行分区 Map<Boolean,List> vd = list.stream().collect(Collectors.partitioningBy(Employee::getManage));
-
-
-
方法 描述 collect(Collector c) 将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
-
Optional类
概念
- 到目前为止,臭名昭著的空指针异常是导致Java应用程序失败的最常见的原因。以前,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类,Guava通过使用检查空值的方式来防止代码污染,它鼓励程序员更干净的代码。受到Google Guava的启发,Optional类已经成为Java 8 类库的一部分
- Optional类(java.util.Optional)是一个容器来,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。原来用null表示一个值不存在,现在Optional可以更好的表达这个概念。并且可以避免空指针异常。
- Optional类的javac描述如下:这是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,则调用get()方法会返回对象
Optional类的方法
-
Optional类提供很多有用的方法,这样我们就不用显式进行空值检测。
-
创建Optional类对象的方法:
-
Optional.of(T t):创建一个Optional实例,t必须非空;
-
Optional.empty():创建一个空的Optional实例
-
Optional.ofNullable(T t):t可以为null
-
/** * - Optional.of(T t):创建一个Optional实例,t必须非空; * - Optional.empty():创建一个空的Optional实例 * - Optional.ofNullable(T t):t可以为null */ @Test public void test(){ Optional<Boy> boy = Optional.of(new Boy()); if (boy.isPresent()) { Boy boy1 = boy.get(); } Optional<Object> empty = Optional.empty(); Optional.ofNullable(null); Optional.ofNullable(new Girl()); }
-
-
判断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接口实现提供的异常
-
public String getGirlName2(Boy boy){ Optional<Boy> boy1 = Optional.ofNullable(boy); Boy boy2 = boy1.orElse(new Boy()); Optional<Girl> girl = Optional.ofNullable(boy2.getGirl()); Girl girl1 = girl.orElse(new Girl()); return girl1.getName(); } @Test public void test2(){ System.out.println(getGirlName2(new Boy())); }
-
Optional类总结
- optional类避免在程序中出现空指针异常
- 常用方法:
- ofNullable(T t)
- orElse(T t)