Java8新特性学习

Lambda表达式

Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。

(o1, o2) -> Integer.compare(o1, o2);
格式:
-> Lambda操作符
左边:lambda形参列表(接口中的抽象方法的形参列表)
右边:Lambda体(其实就是重写的抽象方法的方法体)
使用:6种方法
本质:作为接口的实例
总结:Lambda形参列表的参数类型可以省晤(类型推断):如果Lambda形参列表只有一个参数,其一对()也可以省略
Lambda体应该使用一对{}包裹;如果Lambda体只有一条执行语句,可能是return,省略括号和return

6种格式

格式1:无参,无返回值

Runnable r1 = new Runnable() {
          @Override
          public void run() {
              System.out.println("123");
          }
      };
      r1.run();
      System.out.println("=============");
      Runnable r2 = () -> {
          System.out.println("Lambda");
      };
      r2.run();

格式2:一个参数,没有返回值

Consumer<String> con = new Consumer<String>() {
    @Override
    public void accept(String s) {
        System.out.println(s);
    }
};
con.accept("谎言和誓言的区别");

Consumer<String> con1 = (String s) -> {
    System.out.println(s);
};
con1.accept("一个是听的人当真了,一个是说的人当真了");

格式3 数据类型可以省略,因为可由编译器推断得出,类型推断

 Consumer<String> con = new Consumer<String>() {
     @Override
     public void accept(String s) {
         System.out.println(s);
     }
 };
 con.accept("谎言和誓言的区别");

 Consumer<String> con1 = (s) -> {
     System.out.println(s);
 };
 con1.accept("一个是听的人当真了,一个是说的人当真了");

类型推断

ArrayList<String> objects = new ArrayList<>();
int[] arr = {1, 2, 3};

格式4 Lambda若只需要一个参数时,参数的小括号可以省略

 Consumer<String> con1 = s -> {
     System.out.println(s);
 };
 con1.accept("一个是听的人当真了,一个是说的人当真了");

格式5 Lambda需要两个或以上的参数,多条执行语句,并且有返回值

Comparator<Integer> com1 = new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        System.out.println(o1);
        System.out.println(o2);
        return Integer.compare(o1, o2);
    }
};
int compare1 = com1.compare(12, 21);
System.out.println(compare1);

Comparator<Integer> com2 = (o1, o2) -> {
    System.out.println(o1);
    System.out.println(o2);
    return Integer.compare(o1, o2);
};
System.out.println(com2.compare(12, 21));

格式6 当Lambda体只有一条语句时,return 与大括号若有,都可以省略

Comparator<Integer> com2 = (o1, o2) -> Integer.compare(o1, o2);
System.out.println(com2.compare(12, 21));

函数式接口

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

你可以通过Lambda表达式来创建该接口的对象。(若Lambda表达式抛出一个受检异常(非运行时异常),那么该异常需要在目标接口的抽象方法上进行声明)。

我们可以在一个接口上使用@Functionallnterface注解,这样做可以检查它是否是一个函数式接口。同时javadoc也会包含一条声明,说明这个接口是一个函数式接口。

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

  • Javal从诞生之日起就是一直倡导“一切皆对象”,在Java里面面向对象(OOP)编程是一切。但是随着python、scala等语言的兴起和新技术的挑战,Java不得不做出调整以便支持更加广泛的技术要求,也即java不但可以支持OOP还可以支持OOF(面向函数编程)
  • 在函数式编程语言当中,函数被当做一等公民对待。在将函数作为一等公民的编程语言中,Lambda表达式的类型是函数。但是在Java8中,有所不同。在Java8中,Lambda表达式是对象,而不是函数,它们必须依附于一类特别的对象类型——函数式接口。
  • 简单的说,在Java8中,Lambda表达式就是一个函数式接口的实例。这就是Lambda表达式和函数式接口的关系。也就是说,只要一个对象是函数式接口的实例,那么该对象就可以用Lambda表达式来表示。
  • 所以以前用匿名实现类表示的现在都可以用Lambda表达式来写。
  • 不是所有的匿名实现类都可以用Lambda表达式写,只有是函数式接口的匿名实现类才可以

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

消费型接口 Consumer void accept(T t)

供给型接口 Supplier T get()

函数型接口 Function<T,R> R apply(T t)

断定型接口 Predicate boolean test(T t)

方法引用

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

本质上就是Lambda表达式,而Lambda表达式作为函数式接口的实例。所以方法引用,也是函数式接口的实例

使用格式: 类(或对象)::方法名


3种情况

对象::非静态方法

类::静态方法

类:非静态方法


构造器引用

函数式接口的抽象方法的形参列表和构造器的形参列表一致。

抽象方法的返回值类型即为构造器所属的类的类型

空参构造器

Supplier<Employee> sup = Employee :: new;

数组引用

Function<Integer,String[]> fun = String[] :: new;

Stream API

  • Java8中有两大最为重要的改变。第一个是Lambda表达式;另外一个则是Stream APl。|I
  • Stream APl ( java.util.stream)把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充,因为Stream API可以极大提供Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
  • Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用
    Stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询。也可以使用Stream API来并行执行操作。简言之,Stream API提供了一种高效且易于使用的处理数据的方式。

为什么需要使用Stream API

  • 实际开发中,项目中多数数据源都来自于Mysdl,Oracle等。但现在数据源可以更多了,MongDB,Radis等,而这些NoSQL的数据就需要Java层面去处理。
  • Stream和 Collection集合的这别: Collection是一种静态的内存数据结构,而Stream是有关计算的。前者是主要面向内存,存储在内存中,后者主要是面向CPU,通过CPU实现计算。

什么是Stream

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

注意:
stream自己不会存储元素。
stream不会改变源对象。相反,他们会返回一个持有结果的新Stream

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

Stream操作的三个步骤

  • 创建Stream
    • 一个数据源(如:集合、数组〉,获取一个流
  • 中间操作
    • 一个中间操作链,对数据源的数据进行处理
  • 终止操作(终端操作)
    • 一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用

创建Stream

通过集合

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

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

 public static List<User> getUser() {
        List<User> users = new ArrayList<>();
        users.add(new User("123", "456", 11));
        users.add(new User("23", "456", 22));
        users.add(new User("3", "456", 33));
        return users;
    }
---
List<User> user = UserData.getUser();
Stream<User> stream = user.stream();
Stream<User> userStream = user.parallelStream();
通过数组

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)
 int[] arr = {1, 2, 3, 4};
 IntStream stream = Arrays.stream(arr);
 User u = new User("1", "1", 22);
 User u2 = new User("2", "1", 22);
 User[] u3 = new User[]{u, u2};
 Stream<User> stream1 = Arrays.stream(u3);
通过Stream的of()

可以调用Stream类静态方法 of(),通过显示值创建一个流。它可以接收任意数量的参数。

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

Stream<Integer> integerStream = Stream.of(1, 2, 3, 4);
创建无限流

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

迭代
public static Stream iterate(final T seed, final UnaryOperatorf)

生成
public static Stream generate(Suppliers)

//遍历前10个偶数
Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);
//生成10个随机数
Stream.generate(Math::random).limit(10).forEach(System.out::println);

Stream的中间操作

多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。

筛选与切片

在这里插入图片描述

 List<User> user = UserData.getUser();
 Stream<User> stream = user.stream();
 stream.filter(u -> u.getAge() > 1).forEach(System.out::println);

因为只能用一次,所以要像使用迭代器那样重新生成新的stream

user.stream().limit(2).forEach(System.out::println);
user.stream().skip(1).forEach(System.out::println);
user.stream().distinct().forEach(System.out::println);
映射

在这里插入图片描述

List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);
List<User> user = UserData.getUser();
Stream<Integer> integerStream = user.stream().map(User::getAge);
integerStream.filter(age -> age > 3).forEach(System.out::println);

map与flatMap的区别就像是list.add和list.addAll的区别

//用map做
Stream<Stream<Character>> streamStream = list.stream().map(StreamAPITest1::fromStringToStream);
streamStream.forEach(s -> {
    s.forEach(System.out::println);
});
//用flatMap
Stream<Character> characterStream = list.stream().flatMap(StreamAPITest1::fromStringToStream);
characterStream.forEach(System.out::println);
---
public static Stream<Character> fromStringToStream(String str) {
List<Character> list = new ArrayList<>();
for (Character c : str.toCharArray()) {
list.add(c);
}
return list.stream();
}
排序

在这里插入图片描述

List<Integer> integers = Arrays.asList(12, 33, 55, 44, -5);
integers.stream().sorted().forEach(System.out::println);

//自然需要实现Comparable接口
List<User> user = UserData.getUser();
user.stream().sorted((u1, u2) -> {
return Integer.compare(u1.getAge(), u2.getAge());
}).forEach(System.out::println);
user.stream().sorted((u1, u2) -> {
int ageValue = Integer.compare(u1.getAge(), u2.getAge());
if (ageValue != 0) {
return ageValue;
}else {
return Double.compare(u1.getSal(), u2.getSal());
}
}).forEach(System.out::println);

终止操作

终止操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如: List、 Integer,味至是void 。

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

匹配与查找

在这里插入图片描述

在这里插入图片描述

List<User> user = UserData.getUser();
long count = user.stream().filter(e -> e.getAge() > 1).count();
System.out.println(count);
Optional<Integer> max = user.stream().map(e -> e.getAge()).max(Integer::compare);
System.out.println(max);
Optional<User> min = user.stream().min((u1, u2) -> Integer.compare(u1.getAge(), u2.getAge()));
System.out.println(min);
//内部迭代
user.stream().forEach(System.out::println);
//外部迭代
user.forEach(System.out::println);
内部迭代
user.stream().forEach(System.out::println);
外部迭代
user.forEach(System.out::println);
规约

在这里插入图片描述

map 和 reduce的连接通常称为map-reduce模式,因Google用它来进行网络搜索而出名。

List<Integer> integers = Arrays.asList(1, 2, 3, 4);
Integer reduce = integers.stream().reduce(0, Integer::sum);
System.out.println(reduce);

List<User> user = UserData.getUser();
Stream<Integer> integerStream = user.stream().map(User::getAge);
Optional<Integer> reduce1 = integerStream.reduce(Integer::sum);
System.out.println(reduce1);
收集

在这里插入图片描述

Collector接口中方法的实现决定了如何对流执行收集的操作(如收集到 List、Set.Map)。
另外,Collectors实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:

在这里插入图片描述

List<User> user = UserData.getUser();
List<User> collect = user.stream().filter(u -> u.getAge() > 1).collect(Collectors.toList());
System.out.println(collect);

在这里插入图片描述

Optional类

  • 到目前为止,臭名昭著的空指针异常是导致Java应用程序失败的最常见原因。以前,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类,Guava通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代码。受到Google Guava的启发,Optional类已经成为Java8类库的一部分。
  • Optional类(java.util.Optional)是一个容器类,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。原来用null表示一个值不存在,现在Optional可以更好的表达这个概念。并且可以避免空指针异常。
  • Optional类的Javadoc描述如下:这是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。

创建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 orElse Throw(Supplier<? extends X>exceptionSupplier):如果有值则将其返回,否则抛

出由Supplier接口实现提供的异常。

@Test
public void test1() {
    Girl girl = new Girl();
    //of(T t)保证t非空
    Optional<Girl> optionalGirl = Optional.of(girl);
}
@Test
public void test2() {
    Girl girl = new Girl();
    girl = null;
    Optional<Girl> optionalGirl = Optional.ofNullable(girl);
    System.out.println(optionalGirl);
}

orELse(T t):如果Optional内部封装的t是非空的,则返回内部的t。如果内部的是空的,则返回orELse()方法中的参数

@Test
public void test1() {
    Girl girl = new Girl();
    //of(T t)保证t非空
    Optional<Girl> optionalGirl = Optional.of(girl);
}

@Test
public void test2() {
    Girl girl = new Girl();
    girl = null;
    Optional<Girl> optionalGirl = Optional.ofNullable(girl);
    System.out.println(optionalGirl);
}

public String getGirlName(Boy boy) {
    return boy.getGirl().getName();
}

@Test
public void test3() {
    Boy boy = new Boy();
    String girlName = getGirlName(boy);
    System.out.println(girlName);
}

public String getGirlNameNew(Boy boy) {
    if (boy != null) {
        Girl girl = boy.getGirl();
        if (girl != null) {
            return girl.getName();
        }
    }
    return boy.getGirl().getName();
}

//orELse(T t):如果Optional内部封装的t是非空的,则返回内部的t。如果内部的是空的,则返回orELse()方法中的参数
public String getGirlNameByOptional(Boy boy) {
    Optional<Boy> boyOptional = Optional.ofNullable(boy);
    Boy boy1 = boyOptional.orElse(new Boy(new Girl("迪丽热巴")));
    Girl girl = boy1.getGirl();
    Optional<Girl> girlOptional = Optional.ofNullable(girl);
    Girl girl1 = girlOptional.orElse(new Girl("古力娜扎"));
    return girl1.getName();

}

@Test
public void test5() {
    Boy boy = new Boy();
    boy = new Boy(new Girl("123"));
    String girlName = getGirlNameByOptional(boy);
    System.out.println(girlName);
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值