Java8之新特性学习

145 阅读11分钟

lamebda表达式

概念:Lambda的设计者们为了让现有的功能与Lambda表达式良好兼容,考虑了很多方法,于是产生 了函数接口这个概念。这个接口只有一个抽象方法情况下就叫函数式接口,这样的接口可以为Lambda 表达式。

lambda表达式的使用情况(3种)

无参无返回值

Runnable r1=new Runnable() {
@Override
public void run() {
System.out.println("hellow word");
}
};
r1.run();
//通过lambda方式来写
Runnable r2= ()->{
System.out.println("hellow word");
};
r2.run();

有参数无返回值

Consumer co = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
co.accept("hello word");
//lambda
Consumer co1 = (s) -> {
System.out.println(s);
};
co1.accept("wtz");
}

有参有返回值

Comparator<Integer> comparator = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) {
    System.out.println(o1); 
    System.out.println(o2);
    return o1.compareTo(02); 
            } 
        };
 int compare = comparator.compare(9, 8);
 System.out.println(compare); 
 Comparator<Integer> comparator1 = (o1,o2)->{ 
     System.out.println(o1); 
     System.out.println(o2); 
     return o1.compareTo(02); 
 };
 int compare1 = comparator1.compare(7, 8); 
 System.out.println(compare1); 
 }

总结:

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表 达式返回了一个数值

函数式接口

概念:只包含一个抽象方法的接口,称为函数式接口,可以在接口上使用@FunctionalInterface接口 来检验他是否是一个函数式接口

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

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

Stream API

Stream是java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以完成一些复 杂的查找,过滤和映射数据等操作。使用StreamAPI对集合数据进行操作,也可以操作类似于使用SQL进 行查询。这些都可以基于Stream API来并行操作。本质:就是提供一种更加高效方式对操作数据。

在实际开发过程中我们的数据都是来自关系型数据库,例如Mysql,Oracle。随着现在数据源越来越 多,例如MongDB,Redis等这些非关系型数据库的产生就需要我们在java层面去对这些查询到的数据进 行一个处理。

Stream和Collection集合的区别:Collection是一容器,是用来存储数据得,而Stream用来操作容器中的数据,例如过滤,或者是映射等等。前者存储在内存中。后者主要用于计算。

用来对源数据处理(数据是在集合中,例如我们学习过迭代器)

Stream操作方式带有延迟性 获取一个数据源(source)→ 数据转换→执行操作获取想要的结果,每次转换原有 Stream 对象不改变,返回一个新的 Stream 对象(可以有多次转换),这就允许对其操作可以像链条一样排列,变成一 个管道。

Stream 创建

  1. 创建Stream方式一:集合
//创建Stream流,返回一个顺序流
List<Integer> list = Arrays.asList(1, 2, 4, 5, 6);
Stream<Integer> stream = list.stream();
//创建Stream流,返回一个并行流
Stream<String> stringStream = list.parallelStream();

总结:stream()它拿到的数据是一个有序的。parallelStream()像我们多线程同时多个去取所以顺序无法保证称为并行流

  1. 创建Stream方式一:数组
int[] a={1,5,7,8};
IntStream stream1 = Arrays.stream(a);

总结:如果数组是Int类型你的返回值也是INT类型,如果是自定义类型,返回值类型是Stream

  1. 创建Stream方式三:Stream of()流返回其元素为指定值的顺序有序流
Stream<String> man = Stream.of("a","b","c");
man.forEach(t-> System.out.println(t));
  1. 创建Stream方式四:创建无限流
Stream.generate(()->Math.random()).limit(4).forEach(t->
System.out.println(t));

总结:当我们需要用Stream生成一些随机数的时候我们可以用这两个流

过滤

方法描述
filter(Predicatee)接收Lambda,从流中排除某些元素
distinct()筛选,通过流生成的元素的hascode()和equals()去重复元素
limit(long maxSize)截断流,使其元素不超过指定给的数量
skip(long n)跳过元素,返回 一个扔掉前n个元素的流,若流中不足n个元素,则返回一个空流,与limit(n)互补
  • filter
//从流中排除某些元素
Arrays.stream(students).filter(s->s.getAge().equals(16)).forEach(t->
System.out.println(t));
  • distinct (去重)
list.stream().distinct().forEach(t->System.out.println(t));
  • limit(从0开始)
list.stream().limit(2).forEach(t->System.out.println(t));
  • skip(从0开始)
list.stream().skip(2).forEach(t->System.out.println(t));

映射

作用就是把 inputStream 的每一个元素,映射成 output Stream 的另外一个元素

方法描述
map(Functionf)接收一个函数为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
List<Integer> list = Arrays.asList(1, 6, 8, 9);
list.stream().map(n->n*2).collect(Collectors.toList()).forEach(t->
System.out.println(t));

//过滤钱某
Student s1 = new Student("赵",15,"男");
Student s2 = new Student("钱",16,"男");
Student s3 = new Student("孙",17,"男");
List<Student> students = Arrays.asList(s1,s2,s3);
// 方式一
students.stream()
.map(s->s.getName())
.filter(s->s.equals("钱"))
.forEach(t-> System.out.println(t));
//方式二
students.stream().forEach(t->{
String name = t.getName();
if(name.equals("钱")){
System.out.println(t.getSex());
System.out.println(t.getName());
System.out.println(t.getAge());
}
});

总结:从上面例子可以看出,map 生成的是个 1:1 映射,每个输入元素,都按照规则转换成为另外一个 元素。

排序

方法描述
sorted()产生一个新流,其中按照自然排序
sorted(Comparator com)产生一个新流,其中按比较器顺序排序
  • 自然排序
List<Integer> list= Arrays.asList(1,2,-10,6,7,9);
list.stream().sorted().forEach(t->System.out.println(t));
  • 自定义排序
Student s1 = new Student("赵",15,"男");
Student s2= new Student("钱",16,"男");
Student s3 = new Student("孙",17,"男");
Student[] students=new Student[]{s1,s2,s3};
Arrays.stream(students).sorted((e1,e2)->{
return Integer.compare(e1.getAge(),e2.getAge());
}).forEach(t-> System.out.println(t));

终止操作

方法描述
allMatch(Predicate p)检查是否匹配所有元素
anyMatch(Predicate p)检查是否至少匹配一个元素
noneMatch(Predicate p)检查是否没有匹配所有元素
findFirst()返回第一个元素
findAny()返回当前流中的任意元素
count返回流中元素总个数
max获取最大值
min最小值
forEach()迭代
Student s1 = new Student("赵",15,"男");
Student s2= new Student("钱",16,"男");
Student s3 = new Student("孙",17,"男");
List<Student> students = Arrays.asList(s1, s2, s3);

//allMatch(Predicate p)
boolean b = students.stream().allMatch(e -> e.getAge() > 13 && e.getAge() < 17);
//anyMatch(Predicate p)
boolean b2 = students.stream().anyMatch(e -> e.getAge() > 13 && e.getAge() <
17);
//noneMatch(Predicate p)
Optional<Student> first = students.stream().findFirst();
//findFirst()
Optional<Student> first = Arrays.stream(students).findFirst();
System.out.println(first)
//findAny()
Optional<Student> any = students.parallelStream().findAny();
//count()
long count = students.stream().count();
//max
Stream<Integer> integerStream = students.stream().map(st -> st.getAge());
Optional<Integer> max = integerStream.max((e1, e2) -> {
return Integer.compare(e1, e2);
});
System.out.println(max);
//min
Stream<Integer> integerStream = students.stream().map(st -> st.getAge());
Optional<Integer> min = integerStream.min((e1, e2) -> {
return Integer.compare(e1, e2);
});
System.out.println(min);

归约

Reduce中文含义为:减少、缩小;而Stream中的Reduce方法干的正是这样的活:根据一定的规则将 Stream中的元素进行计算后返回一个唯一的值。

//对所有年龄进行累加

//归约
Student s1 = new Student("赵",15,"男");
Student s2= new Student("钱",16,"男");
Student s3 = new Student("孙",17,"男");
List<Student> students = Arrays.asList(s1, s2, s3);
Stream<Integer> integerStream = students.stream().map(e -> e.getAge());
Optional<Integer> reduce = integerStream.reduce(new
BinaryOperator<Integer>() {
@Override
public Integer apply(Integer i1, Integer i2) {
return i1 + i2;
}
});
System.out.println(reduce);
}

Optional类

概念:Optional类是Java8为了解决null值判断问题,借鉴google guava类库的Optional类而引入的一 个同名Optional类,使用Optional类可以避免显式的null值判断(null的防御性检查),避免null导致的NPE(NullPointerException)。

Optional类提供的方法

方法描述
of把指定的值封装为Optional对象,如果指定的值为null,则抛出NullPointerException
empty创建一个空的Optional对象
ofNullable把指定的值封装为Optional对象,如果指定的值为null,则创建一个空的Optional对象
get如果创建的Optional中有值存在,则返回此值,否则抛出NoSuchElementException
orElse如果创建的Optional中有值存在,则返回此值,否则返回一个默认值
orElseGet如果创建的Optional中有值存在,则返回此值,否则返回一个由Supplier接口生成的值
orElseThrow如果创建的Optional中有值存在,则返回此值,否则抛出一个由指定的Supplier接口生成的异常
filter如果创建的Optional中的值满足filter中的条件,则返回包含该值的Optional对象,否则返回一个空的Optional对象
map如果创建的Optional中的值存在,对该值执行提供的Function函数调用
flagMap如果创建的Optional中的值存在,就对该值执行提供的Function函数调用,返回一个Optional类型的值,否则就返回一个空的Optional对象
isPresent如果创建的Optional中的值存在,返回true,否则返回false
ifPresent如果创建的Optional中的值存在,则执行该方法的调用,否则什么也不做
  • Optional.of(T value) 该方法通过一个非 null 的 value 来构造一个 Optional,返回的 Optional 包含了value 这个值。对于该方法,传入的参数一定不能为 null,否则便会抛出 NullPointerException。
//创建一个值为张三的String类型的Optional
Optional<String> ofOptional = Optional.of("张三");
  • Optional.ofNullable(T value), 该方法和 of 方法的区别在于,传入的参数可以为 null , 原来该方法会判断传入的参数是否为 null,如果为 null 的话,返回的就是 Optional.empty()。
//创建一个值为lisi的String类型的Optional
Optional<String> nullOptional = Optional.ofNullable("lisi");
  • Optional.empty() 该方法用来构造一个空的 Optional,即该 Optional 中不包含值,其实底层实现还是如果 Optional 中的 value 为 null 则该 Optional 为不包含值的状态,然后在 API 层面将 Optional 表现的不能包含 null 值,使得 Optional 只存在 包含值 和 不包含值 两种状态。
//创建一个空的String类型的Optional对象
Optional<String> emptyOptional = Optional.empty();
  • get() 该方法用来获取Optional对象,如果我们创建的Optional对象中有值存在则返回此值,如果没有值存在,则会抛出NoSuchElementException异常
Optional<String> stringOptional = Optional.of("张三");
System.out.println(stringOptional.get());
  • orElse(T) 该方法用来获取Optional对象,如果创建的Optional中有值存在,则返回此值,否则返回一个默认值。
Optional<String> stringOptional = Optional.of("张三");
System.out.println(stringOptional.orElse("zhangsan"));

Optional<String> emptyOptional = Optional.empty();
System.out.println(emptyOptional.orElse("李四"));
  • orElseGet(T) 该方法用来获取Optional对象,如果创建的Optional中有值存在,则返回此值,否则返回一个由Supplier接口生成的值
Optional<String> stringOptional = Optional.of("张三");
System.out.println(stringOptional.orElseGet(() -> "zhangsan"));

Optional<String> emptyOptional = Optional.empty();
System.out.println(emptyOptional.orElseGet(() -> "orElseGet"));
  • orElseThrow(RuntimeException) 如果创建的Optional中有值存在,则返回此值,否则抛出一个由指定的Supplier接口生成的异常
Optional<String> stringOptional = Optional.of("张三");
System.out.println(stringOptional.orElseThrow(CustomException::new));

Optional<String> emptyOptional = Optional.empty();
System.out.println(emptyOptional.orElseThrow(CustomException::new));

private static class CustomException extends RuntimeException {
   private static final long serialVersionUID = -4399699891687593264L;

   public CustomException() {
       super("自定义异常");
   }

   public CustomException(String message) {
      super(message);
   }
  }
  • filter() 如果创建的Optional中的值满足filter中的条件,则返回包含该值的Optional对象,否则返回一个空的Optional对象
Optional<String> stringOptional = Optional.of("zhangsan");
System.out.println(stringOptional.filter(e -> e.length() > 5).orElse("王五"));
stringOptional = Optional.empty();
System.out.println(stringOptional.filter(e -> e.length() > 5).orElse("lisi"));

注意Optional中的filter方法和Stream中的filter方法是有点不一样的,Stream中的filter方法是对一堆元素进行过滤,而Optional中的filter方法只是对一个元素进行过滤,可以把Optional看成是最多只包含一个元素 的Stream。

  • map 如果创建的Optional中的值存在,对该值执行提供的Function函数调用
//map方法执行传入的lambda表达式参数对Optional实例的值进行修改,修改后的返回值仍然是一个Optional对象
Optional<String> stringOptional = Optional.of("zhangsan");
System.out.println(stringOptional.map(e -> e.toUpperCase()).orElse("失败"));

stringOptional = Optional.empty();
System.out.println(stringOptional.map(e -> e.toUpperCase()).orElse("失败"));
  • flagMap 如果创建的Optional中的值存在,就对该值执行提供的Function函数调用,返回一个Optional类型的值,否则就返回一个空的Optional对象.flatMap与map(Funtion)方法类似,区别在于flatMap中的mapper返回值必须是Optional,map方法的mapping函数返回值可以是任何类型T。调用结束时,flatMap不会对结果用Optional封装。
//map方法中的lambda表达式返回值可以是任意类型,在map函数返回之前会包装为Optional。 
//但flatMap方法中的lambda表达式返回值必须是Optionl实例
Optional<String> stringOptional = Optional.of("zhangsan");
System.out.println(stringOptional.flatMap(e -> Optional.of("lisi")).orElse("失败"));

stringOptional = Optional.empty();
System.out.println(stringOptional.flatMap(e -> Optional.empty()).orElse("失败"));
  • ifPresent 如果创建的Optional中的值存在,则执行该方法的调用,否则什么也不做
//ifPresent方法的参数是一个Consumer的实现类,Consumer类包含一个抽象方法,
该抽象方法对传入的值进行处理,只处理没有返回值。
Optional<String> stringOptional = Optional.of("zhangsan");
stringOptional.ifPresent(e-> System.out.println("我被处理了。。。"+e));