Java8新特性

Java8新特性

Lambda表达式

例子:

Runnable r1 = new Runnable() {
              @Override
              public void run() {
                   System.out.println("common");
                 }
 			};
r1.run();
 ====================================================
Runnable r2 = ()-> System.out.println("Lambda");
        Comparator<Integer> com1 = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2);
            }
        };
        int compare1 = com1.compare(12,21);
        System.out.println(compare1);
        
      //Lambda表达式
        Comparator<Integer> com2 = (o1, o2) ->Integer.compare(o1,o2);
        int compare2 = com2.compare(12,21);
        System.out.println(compare2);
	 //方法引用
        Comparator<Integer> com3 = Integer::compare;
        int compare3 = com3.compare(12,21);
        System.out.println(compare3);

举例:Runnable r2 = (o1, o2) -> Integer.compare(o1,o2);

	  接口名   引用名 = (参数列表)   ->  {语句块};

格式:

​ ->:Lambda操作符(箭头操作符)

​ ->:左边:lambda的形参列表(其实就是接口中的抽象中抽象方法的形参列表)

​ ->:右边:lambda体(其实就是重写的抽象方法的方法体)

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

总结:

  1. ->左边:lambd形参列表的类型可以省略,如果只有一个参数可以省略括号;

  2. ->右边:lambda体应该使用一对{}包裹;如果lambda体只有一条执行语句(可能是return语句),可以省略这一对{}和return关键字;

lambda表达式的本质:函数式接口的’'实例"

(如果一个接口中只声明了一个抽象方法,那么我们称为函数式接口[functional interface])

语法格式1:无参数,无返回值;

Runnable r2 = ()-> System.out.println("Lambda");

语法格式2:有一个参数,但是没有返回值;

    public static void main(String[] args) {
        Consumer <String> con1 = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con1.accept("aha!");
===========================================================
    //开始lambda
        Consumer <String> con2 = (String s) -> {
            System.out.println(s);
        };
        con2.accept("Well done!");
    }

这里如果只有一条语句的话,是可以省略掉{}的;

语法格式3:数据类型可以省略(前提是:编译器可以推断出数据类型,称为“类型推断”

如果前面已经明确泛型了,那么参数列表的String也是可以省略的;

Consumer <String> con2 = (s) -> System.out.println(s);

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

Consumer <String> con2 = s -> System.out.println(s);

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

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

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

Comparator<Integer> com2 = (o1, o2) -> o1.compareTo(o2);

函数式接口

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

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

以后可以选择合适的接口,写对应函数的lambda来解决;

    public static void main(String[] args) {
        Consumer<Integer> con = times -> System.out.println("ლ(′◉❥◉`ლ)"+times+"times!");
        test1(3000,con);
    }
    public static void test1(int times, Consumer<Integer> con){
        con.accept(times);
    }

上面这段还可以进一步继续简化:

    public static void main(String[] args) {
        test1(3000,times -> System.out.println("ლ(′◉❥◉`ლ)"+times+"times!"));
    }
    public static void test1(int times, Consumer<Integer> con){
        con.accept(times);
    }

直接当做参数传入方法(因为本质就是接口实例化)


方法引用

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

  2. 要求:实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致!

  3. 格式:使用操作符“::”将类(或对象)与方法名分割开来;

     		**类(或对象) ::	方法名**
    
  4. 三种主要使用情况:

    1. 情况一: 对象 :: 非静态方法

      Consumer中的void accept(T t)

      PrintStream 中的void println(T t)

      参数列表相同,返回类型相同,符合使用条件

    public static void main(String[] args) {
    PrintStream ps = System.out;
    Consumer con = ps :: println;
    con.accept(“夜色哪里都是美…”);
    }

    
    
    
    Supplier中的T get()
    
    Integer中的String toString()
    
    ```java
    public static void main(String[] args) {
            Integer integer = new Integer(1);
            Supplier<String> sup = () -> integer.toString();
            System.out.println(sup.get());
        }
    
    1. 情况二: 类 :: 静态方法

    Comparator中的int compare(T t1, T t2)

    Integer中的int compare(T t1, T t2)

    参数列表和返回类型两个条件都符合,可以使用;

     public static void main(String[] args) {
            Comparator<Integer> com = Integer :: compare;
            System.out.println(com.compare(12,21));
        }
    

    Function中的R apply(T t)

    Math中的Long round(Double d)

     public static void main(String[] args) {
            Function<Double,Long> func = Math::round;
            System.out.println(func.apply(10.0));
        }
    
    1. 情况三:类 :: 实例方法

      Comparator中的int compare(T t1, T t2)

      String 中的int t1.compareTo(t2)

      compare的第一个参数t1 正好 作为调用String实例方法的对象t1,那我们就可以使用了;

          public static void main(String[] args) {
              Comparator<String> com = String::compareTo;
              System.out.println(com.compare("a","b"));
          }
      

      Function中的R apply(T t);

      Person中的String getName();

      apply的第一个参数t正好是调用getName()的对象,所以符合条件可以使用;

      public class test {
          public static void main(String[] args) {
              Function<Person,String> func = Person :: getName;
              System.out.println(func.apply(new Person()));
          }
      }
      class Person{
          private String name = "Nobody";
      
          public String getName() {
              return name;
          }
      }
      

构造器引用

和方法引用类似,抽象方法返回的值就是类的对象

示例:

Supplier中的get()

Employee的空参构造器:Employee()

构造器没有参数,get方法也没有参数,所以可以把无参构造器塞给get();

    public static void main(String[] args) {
        //Lambda写法:
        Supplier<Person> supplier = () -> new Person();
        System.out.println(supplier.get());
        =================================
       //构造器写法:
        Supplier<Person> supplier = Person::new;
        System.out.println(supplier.get());
    }

注意这里 Peson::new ,表示调用的是默认的无参构造器;如果要调用其他有参构造器就不能使用Supplier了,得用其他有参数的接口方法;

比如:

Function中的R apply(T t)

Person的有参构造器Person(String s)

两个方法参数个数一致,类型一致(可通过泛型指定Function的类型),那么符合条件;

public static void main(String[] args) {
      Function<String,Person> func = Person::new;
      System.out.println(func.apply("Year!!!"));
    }
...
    public Person(String name) {
        this.name = name;
    }

不用显势声明调用哪个构造器,只要保证参数列表一致即可;


数组引用

可以把数组看作是一个特殊的类,则写法与构造器引用一致。

    public static void main(String[] args) {
        //Lambda写法
      Function<Integer,String[]> func1 = length -> new String[length] ;
      String[] arr1 = func1.apply(10);
      System.out.println(arr1.length);
	   //数组引用
      Function<Integer,String[]> func2 = String[] :: new;
      String[] arr2 = func2.apply(20);
        System.out.println(arr2.length);
    }

Stream API

注意:只有进行了 终止操作,中间一系列的操作才会执行(有点像flush,所以中间的操作并不是即调即用的)

创建Stream:

方式1:通过集合

    public static void main(String[] args) {
        List<Person> businessmen = Person.getBusinessmen();
        //获得一个顺序流;
        Stream<Person> stream = businessmen.stream();
        //获得一个并行流;
        Stream<Person> parallelStream = businessmen.parallelStream();
    }

注意两种不同的流;

方式2:通过数组

    public static void main(String[] args) {
        int []arr = {1,2,3,4,5,6};
        IntStream intStream = Arrays.stream(arr);
        
        double []doubles = {1.0,2.0,3.0};
        DoubleStream doubleStream = Arrays.stream(doubles);
        
        Person xiaomi = new Person("小米");
        Person apple = new Person("苹果");
        Person[] people = new Person[]{xiaomi,apple};
        Stream<Person> stream = Arrays.stream(people);
    }

Arrays类的static Stream stream(T[] array):返回一个(类型正确匹配的)流

方式3:通过Stream的of()

    public static void main(String[] args) {
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
        Stream<? extends Number> stream = Stream.of(1.0, 2, 3);
        Stream<Double> doubleStream = Stream.of(1.0, 2.0, 3.0);
    }

注意一下这边2,3行,如果集合内类型不统一,那么会使用通配符;

方式4:创建无限流(用的较少,了解即可)

迭代:

    public static void main(String[] args) {
      Stream.iterate(0,t->t+2).limit(10).forEach(System.out::println);
    }

生成:

    public static void main(String[] args) {
      Stream.generate(Math::random).limit(10).forEach(System.out::println);
    }

limit和foreach是用来操作和终止的,不是创建流的;流的创建是iterate和generate;

中间操作

筛选与切片

这些操作对流本身不会有影响,流本身不变(有点像String的一系列api,并不会对String本身有改变)

    public static void main(String[] args) {
     List<Person> businessmen = Person.getBusinessmen();
        
	"filter筛选流,从流中排除某些元素,接收lambda"
     Stream<Person> stream1 = businessmen.stream();
     stream1.filter(e ->e.getName().length()>2 ).forEach(System.out::println);
        
	"limit截断流,使其元素不超过n(只处理前n个元素)"
     Stream<Person> stream2 = businessmen.stream();
     stream2.limit(3).forEach(System.out::println);
	
     "skip跳过流,从第n+1个元素开始处理(跳过前n个元素,注意n为long)"
     Stream<Person> stream3 = businessmen.stream();
     stream3.skip(3L).forEach(System.out::println);
	
     "distinct去重流,去掉相同的元素(根据hashCode和equals)"
     Stream<Person> stream4 = businessmen.stream();
     stream4.distinct().forEach(System.out::println);

    }

注意:skip的数如果超过流中元素总数(太大了),那么会返回一个空流。

(每次终结操作之后,这个流就不能用了,所以我们要再重新开流)


映射

map(Function f)—接受一个函数作为参数,将元素转换成其他形式或提取信息,该函数被应用到每一个元素上,并将其映射成一个新的元素。

    public static void main(String[] args) {
        List<String> list = Arrays.asList("aa","bb","c");
        list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);
        
    }

使用map得到一个新的流(map里面写一个函数,返回一个新的流,这个流就是原始流经过函数映射后得到的新流)

    public static void main(String[] args) {
        List<Person> businessmen = Person.getBusinessmen();
        Stream<String> stringStream = businessmen.stream().map(Person::getName);
        stringStream.filter(name->name.length()>2).forEach(System.out::println);
    }

flatMap(Function f)—接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有的流打散,连接成一个流。

先看看两者的不同:

    public void test() {
        List list1 = new ArrayList<>();
        list1.add(1);
        list1.add(2);
        list1.add(3);
        List list2 = new ArrayList<>();
        list2.add(10);
        list2.add(11);
        list2.add(12);
        
        list1.addAll(list2);
        list1.add(list2);
    }

先看看add和addAll的不同吧,

list1: [1,2,3]

list2: [10,11,12]

add后的结果:[1,2,3, [10,11,12] ](未拆散)——————>相当于map

addAll后的结果:[1,2,3,10,11,12](拆散)———————>相当于flatMap

map参数将 字符串转换成流

    public static void main(String[] args) {
        List<Person> businessmen = Person.getBusinessmen();
        Stream<String> stringStream = businessmen.stream().map(Person::getName);
        Stream<Stream<Character>> streamStream = stringStream.map(test::fromStringToStream);
        streamStream.forEach(s -> s.forEach(System.out::println));
    }



    public static Stream<Character> fromStringToStream(String str) {
        ArrayList<Character> list = new ArrayList<>();
        for (Character c : str.toCharArray()) {
            list.add(c);
        }
        return list.stream();
    }

因为未打散,所以便利的时候要两个foreach;

flatMap(Function f)打散了,直接一层foreach就好了;

    public static void main(String[] args) {
        List<Person> businessmen = Person.getBusinessmen();
        Stream<String> stringStream = businessmen.stream().map(Person::getName);
        Stream<Character> streamStream = stringStream.flatMap(test::fromStringToStream);
        streamStream.forEach(System.out::println);
    }



    public static Stream<Character> fromStringToStream(String str) {
        ArrayList<Character> list = new ArrayList<>();
        for (Character c : str.toCharArray()) {
            list.add(c);
        }
        return list.stream();
    }

排序

sorted()——自然排序

    public static void main(String[] args) {
      List<Integer> list = Arrays.asList(12,43,65,7,21,11,-69,8);
      list.stream().sorted().forEach(System.out::println);
    }

sorted(Comparator com)——定制排序

    public static void main(String[] args) {
      List<Integer> list = Arrays.asList(12,43,65,7,21,11,-69,8);
      list.stream().sorted((o1, o2) -> o2.compareTo(o1)).forEach(System.out::println);
    }

终止操作

匹配与查找

allMatch(Predicate p )——检查是否匹配所有元素;(括号内参数写boolean表达式,判断条件)

    public static void main(String[] args) {
        List<Person> businessmen = Person.getBusinessmen();
        boolean allMatch = businessmen.stream().allMatch(person -> person.getName().length() > 0);
    }

anyMatch(Predicate p)——检查是否至少有一个元素匹配条件

    public static void main(String[] args) {
        List<Person> businessmen = Person.getBusinessmen();
        boolean anyMatch = businessmen.stream().anyMatch(person -> person.getName().length() < 0);
    }

noneMatch(Predicate p)——检查是否没有匹配的元素

    public static void main(String[] args) {
        List<Person> businessmen = Person.getBusinessmen();
        boolean noneMatch = businessmen.stream().noneMatch(person -> person.getName().equals("马云"));
    }

有“马云”就false,没有就true;

findFirst()——返回第一个元素

    public static void main(String[] args) {
        List<Person> businessmen = Person.getBusinessmen();
        Optional<Person> first = businessmen.stream().findFirst();
    }

返回的类型是Optinal;

findAny()——返回流中的任意元素(取决于cpu)

    public static void main(String[] args) {
        List<Person> businessmen = Person.getBusinessmen();
        Optional<Person>  any = businessmen.stream().findAny();
    }

返回的类型是Optinal;

count——返回流中元素的总个数

    public static void main(String[] args) {
        List<Person> businessmen = Person.getBusinessmen();
        long count = businessmen.stream().count();
    }

返回类型是long;

max(Comparator com)——返回流中最大值;

    public static void main(String[] args) {
        List<Person> businessmen = Person.getBusinessmen();
        
Optional<Person> max = businessmen.stream().max((o1, o2) -> o1.getName().compareTo(o2.getName()));
}

min(Comparator com)——返回流中最小值

    public static void main(String[] args) {
        List<Person> businessmen = Person.getBusinessmen();
Optional<Person> min = businessmen.stream().min((o1, o2) -> o1.getName().compareTo(o2.getName()));
    }

foreach(Cosumer c)——内部迭代

    public static void main(String[] args) {
        List<Person> businessmen = Person.getBusinessmen();
        businessmen.stream().forEach(System.out::println);
    }

归约

reduce(T identity,BinaryOperator)——可以将流中元素反复结合起来,得到一个值。

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
        Integer sum = list.stream().reduce(0, Integer::sum);
    }

reduce(BinaryOperator)——可以将流中的元素反复结合起来,得到一个值。返回Optional

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
        Optional<Integer> sum = list.stream().reduce(Integer::sum);
    }

这两种reduce最大的区别就是在于参数和返回类型:如果没有identity,那么返回的是Optional;如果有identity,那么返回的是具体的类型;


收集

collect(Collector c)——将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法

    public static void main(String[] args) {
        ArrayList<Person> businessmen = Person.getBusinessmen();
        List<Person> collect = businessmen.stream().filter(person -> person.getName().length() > 2).collect(Collectors.toList());
    }

重点是(Collectors.toList()),这个api要记住;


Optional

常用api

of和ofNullable:创建一个Optional实例,

    public static void main(String[] args) {
        Person person = new Person("Obama");
        Optional<Person> optionalPerson = Optional.of(person);
        person = null;
        Optional<Person> personOptional = Optional.ofNullable(person);
    }

Optional.of()不可以接收null指针,Optional.ofNullable()可以接收null;

Optional.empty()创建一个空的Optional实例;

    public static void main(String[] args) {
        Optional<Person> optionalPerson = Optional.empty();
    }

orElse(T t)和ofNullable(T t)

    public String getGirlName(Boy boy){
        //保证boy
        Optional<Boy> boyOptional = Optional.ofNullable(boy);
        Boy boy1 = boyOptional.orElse(new Boy(new Girl("Monica")));
        
       //保证girl 
        Girl girl = boy1.getGirl();
        Optional<Girl> girlOptional = Optional.ofNullable(girl);
        Girl girl1 = girlOptional.orElse(new Girl("Irene"));
        
        return girl1.getName();
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值