Java8新特性

引入lambda

第一次使用

在test01 我们写了一个内部类 比较大小 实际有用的话就这一句 很麻烦

在test02 用lambda表达式优化

package com.lijiawei;

import org.junit.Test;

import java.net.Inet4Address;
import java.util.Comparator;
import java.util.Map;
import java.util.TreeSet;

public class Testlambda {
    @Test
  public  void test01(){
      //原来使用treeset排序得写一个匿名内部类
      Comparator<Integer> com = new Comparator<Integer>(){
              @Override
              public int compare(Integer o1,Integer o2) {
              return Integer.compare(o1,o2);//实际就这一句话有用
          }
      };
      TreeSet<Integer> ts = new TreeSet<Integer>(com);
      ts.add(2);
      ts.add(1);
      System.out.println(ts);
  }
  @Test
    public void test02(){
        Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
        TreeSet<Integer> ts = new TreeSet<Integer>(com);
        ts.add(2);
        ts.add(1);
      System.out.println(ts);
  }
  @Test
    public void test03(){
    
    }
}

一个需求

查询所有年纪大于20的人

  List<Employee> list = Arrays.asList(
            new Employee("张三",28,5000),
            new Employee("李四",8,10000),
            new Employee("王五",38,2000),
            new Employee("赵六",48,4500)
    );
    @Test
    public void test03(){
        List<Employee> a = filterAge(list);
        System.out.println(a);
    }
//查出年龄大于10岁的
    public  List<Employee> filterAge(List<Employee> list){

        List<Employee> employees = new ArrayList<>();
        for (Employee e :list){
            if(e.getAge()>10){
                employees.add(e);
            }
        }
        return employees;
    }
//查出工资大于5000的
  public  List<Employee> filterAge2(List<Employee> list){

        List<Employee> employees = new ArrayList<>();
        for (Employee e :list){
            if(e.getSalary()>5000){ //和上面的方法就变了这一句话
                employees.add(e);
            }
        }
        return employees;
    }

如果我又加一个需求 要求出工资大于5000并且年龄大于20的人 那是不是又得写一个方法 需求一变 就要改变原来的代码 这样不好

策略模式优化

定义一个接口

package com.Inter;

public interface Myfilter<T> {
    public boolean test(T t);
}

定义实现类

package com.Inter;

import com.pojo.Employee;

public class ImplMyfilter implements Myfilter<Employee>{
    @Override
    public boolean test(Employee employee) {
        return employee.getAge()>35;
    }
}

测试类

public List<Employee> show(List<Employee> list , Myfilter<Employee> im ){
        List<Employee> employees =new ArrayList<>();
    for (Employee employee:list){
        if(im.test(employee)){
            employees.add(employee);
        }
    }
    return employees;
}

    @Test
    public void test04(){
        List<Employee> show = show(list, new ImplMyfilter());//如果需求变了 我把这个实例换一下就行
        System.out.println(show);
    }

如果需求在变 我们只需要增加一个实现类 在调用的时候 new 这个新写的实现类即可 使用场景:商场打折

我们发现策略模式有个缺点 : 创建新功能就得写一个类 所以在优化

匿名内部类优化

匿名内部类直接实现 就不用写类实现了

public void text(){
       List<Employee> l = show(list, new Myfilter<Employee>() {
            @Override
            public boolean test(Employee employee) {
                return employee.getSalary()>5000;
            }
        });
        System.out.println(l);
    }

匿名内部类优化可读性差 所以在优化

lambda表达式优化

 @Test
    public void text(){
       List<Employee> l = show(list,(e) -> e.getSalary()>5000);
        
        System.out.println(l);
    }

还能更简洁 之后使用stream优化 先来学习lambda

lambda语法

注意: j.k1.8以前 匿名内部类引用同级别的变量 那个变量必须显示的写final 8之后默认加了final

-> 操作符分为俩部分 左侧 是抽象类中要重写的方法的参数列表 右侧是要执行的功能

接口中只有一个方法

1无参无返回值

Runnble r = ( ) ->System.Out.Print(“你好”);

2有一个参数无返回值

Consumer c = ( x) ->System.out.Print(“你好”);

只有一个参数 小括号可以不写

3有多个参数有返回值 有多条执行语句

多条语句 使用大括号抱起来

Comparator com= (x,y)->{

​ System.out.Print(“你好”);

​ return Integer.compare(x,y);

}

4 如果只有一条语句

return 和大括号可以省略

Comparator com= (x,y) -> Integer.compare(x,y);

5不写数据类型

上面的xy 都没有写数据类型 因为jjvm编译器可以类型推断

比如 String[] str=[“aa”,“bb”,“cc”] 这里的内容就是推断出来的 如果你分开写就报错

String[] str; str=[“aa”,“bb”,“cc”] //报错

再看这个上面写过的 我们e按下点的时候就提示有getSalary方法 他怎么知道我是什么类型的呢?根据目标类型推断出这是什么类型

List l = show(list,(e) -> e.getSalary()>5000);

因为不能写方法名 当接口有多个方法时java不知道重写的是哪个方法 所以借口不能写多个抽象方法

函数式接口

只有一个抽象方法的接口叫函数式接口 在接口上加注解@FunctionInterface 可以帮我们检查这个接口是不是函数式接口

内置函数式接口

每次们用一个功能 都要自己定义一个函数式接口 java想到了这一点 所以有四个内置的接口

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

public class TestLamda{
        @Test
        public void test(){
            show(100,(a)-> System.out.println("消费了"+a));
    }
      public void show(Integer number, Consumer<Integer> consumer){
          consumer.accept(number);
      }
}

Supplier T get(); 供给型接口

package com.lijiawei;

import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;

public class TestLamda{
        @Test
        public void test(){
        List l = show(10,() -> (int)(Math.random()*10));
            System.out.println(l);
    }
      public List<Integer> show(Integer number, Supplier<Integer> supplier){
            List<Integer> lists = new ArrayList<>();
          for (int i = 0; i <number ; i++) {
              lists.add(supplier.get());
          }
            return lists;
      }
}

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

package com.lijiawei;

import org.junit.Test;

import java.util.function.Function;


public class TestLamda{
        @Test
        public void test(){
         String a = show("    helloworld    ",(x) ->x.trim() );
            System.out.println(a);
    }
      public String show(String str, Function<String,String> function){
            return function.apply(str);
      }
}

predicate boolean test(T t ) 断言型接口

方法引用与构造器引用

若lambda体中的内容已经实现了 我们可以引用

对象::实例方法名

类::静态方法名

类::实例方法名

以下三种写法有个前提 我们写的lambda体的方法的返回值和参数列表要与 函数时接口的抽象方法保持一致

在lambda表达式中 我们写了参数列表 和 方法体并返回了一个东西 这写都是手动写出来的 引用不写但要保持一致

对象::实例方法名

package com.lijiawei;

import org.junit.Test;

import java.util.function.Consumer;

public class TestLamda{
    @Test
    public void show(){

        Consumer<String> consumer1 = System.out::println;
        consumer1.accept("zz");

    }
}

再看一个例子

无参有返回值 Math::random也必须无参无返回值

package com.lijiawei;

import org.junit.Test;

import java.util.function.Consumer;
import java.util.function.Supplier;

public class TestLamda{
    @Test
    public void show(){
        //Supplier<T> T get();
        Empoyee emp = new Employee();
        Supplier<Double> supplier =emp::getAge;
        Double d = supplier.get();
        System.out.println(d);

    }
}

类::静态方法名

package com.lijiawei;

import org.junit.Test;

import java.util.Comparator;
import java.util.function.Consumer;
import java.util.function.Supplier;

public class TestLamda{
    @Test
    public void show(){
        Comparator<Integer> com = Integer::compare;
        int a = com.compare(5,4);
        System.out.println(a);
    }
}

类::实例方法名

先用lambda表达式 需求 比较俩个字符串是否一样

   public void show(){
        BiPredicate<String,String> bp = (x,y)->x.equals(y);
       boolean b =bp.test("a","a");
        System.out.println(b);
    }

为什么类名能调用实例方法呢? 当第一个参数是实例方法的调用者 另一个参数是实例方法的参数时 才能这么调

方法引用格式

 public void show(){
        BiPredicate<String,String> bp = String::equals;
       boolean b =bp.test("a","a");
        System.out.println(b);
    }

构造器引用

如果 方法体是获取对象

Supplier<Employee> s = ()->new Employee();

可以这么写 那用的是有参构造还是无参构造呢 得看函数接口的抽象方法的参数列表有多少个 构造器重载怎么办呢

泛型推断可以该用哪个构造器

Supplier<Employee> s = Employee::new;

StreamAPI

创建流的方式

package com.lijiawei;

import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Stream;

public class TestLamda{
    @Test
    public void show(){
        //1获取流第一种方式 集合获取
        List a = new ArrayList();
        Stream<String> s = a.stream();	
        Stream<String> s1 =a.parallelStream();
        //2数组获取流
        String[] str = new String[10];
        Stream<String> s3 = Arrays.stream(str);
        //3Stream静态方法of
        Stream<String> s4 = Stream.of("a","b");
        //4无限流 迭代
        Stream<Integer> s5= Stream.iterate(0,(x) -> x+2);
        s5.forEach(System.out::println);
        //4无限流 生成
        Stream.generate(()->Math.random())
                .limit(10)
                .forEach(System.out::println);
    }
}

Stream筛选与切片

filter-接收lambda 从流中排除某些元素

limit–截断流 使元素不会超出指定数量

skip(n) --跳过 返回扔掉前n个元素的流 不足n个 则返回空流

distinct --筛选 通过元素生成的hascode和equals 去除重复元素

多个中间操作可以形成流水线 除非触发终止操作 否则中间操作不会做任何处理,在终止操作时全部一次性处理,这叫惰性求值

package com.lijiawei;

import org.junit.Test;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Stream;

public class TestLamda{
    List<Employees> employees = Arrays.asList(
            new Employees("张三",18,5000),
            new Employees("张三",18,5000),
            new Employees("张三",18,5000),
            new Employees("李三",20,10000),
            new Employees("王三",30,15000)
    );
    @Test
    public void show(){
        Stream s = employees.stream()
                            .filter((e)->e.getAge()>20);
        //终止操作
        s.forEach(System.out::println);


    }
    @Test
    public void test2(){
        employees.stream()
                .limit(2)
                .forEach(System.out::println);
    }
    @Test
    public void test3(){
        employees.stream()
                //跳过前俩个
                .skip(2)
                .forEach(System.out::println);
    }
    @Test
    //筛选 
    public void test4(){
        employees.stream()
                .distinct()
                .forEach(System.out::println);
    }
}

Stream映射

map --接收lambda 将函数 作用到流的每一个元素上

package com.lijiawei;

import org.junit.Test;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Stream;

public class TestLamda{
    List<Employees> employees = Arrays.asList(
            new Employees("张三",18,5000),
            new Employees("张三",18,5000),
            new Employees("张三",18,5000),
            new Employees("李三",20,10000),
            new Employees("王三",30,15000)
    );
    @Test
    public void show() {
        employees.stream()
                .map((x)->x.getAge())
                .forEach(System.out::println);
    }
}

flagmap 接受一个函数作为参数 将流中的每个值转换成一个流 然后把所有流链接成一个流

package com.lijiawei;

import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class TestLamda{
    @Test
    public void show() {
    List<String> list = Arrays.asList("aa","bb","cc");
        Stream<Character> s = list.stream()
                .flatMap(TestLamda::get);
        s.forEach(System.out::print);
    }
    public static Stream get(String str){
        List l = new ArrayList();
        for (Character c : str.toCharArray()){
            l.add(c);
        }return l.stream();
    }
}

map和flagmap的对比:map好比集合里添加了一个集合 flagmap好比 把集合中的元素添加到另一个集合

map 对每一个元素都看做一个流 处理完之后在把这些流放到一个流里Stream<Stream>

flagmap把所有元素都处理完放到一个流里Stream

排序

sorted() 自然排序 Comparable

sorted(Comparator) 自定义排序 Comparator

package com.lijiawei;

import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class TestLamda{
    @Test
    public void show() {
    List<String> list = Arrays.asList("c","bb","d");
        list.stream()
            .sorted()
            .forEach((x)->System.out.println(x));
    }

}

查找与匹配

package com.lijiawei;

import org.junit.Test;

import javax.swing.text.html.Option;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

public class TestLamda{
    List<Employees> employees = Arrays.asList(
            new Employees("张三",18,5000),
            new Employees("asd三",18,5000),
            new Employees("张das三",18,5000),
            new Employees("李三",20,10000),
            new Employees("王三",30,15000)
    );
    @Test
    public void show() {
        //判断名字是否都是张三  allMatch
        Boolean s = employees.stream()
                .allMatch((e)->e.getName().equals("张三"));
        System.out.println(s);

    }
    @Test
    public void show1() {
        //判断是否有名字是张三  anyMatch
        Boolean s = employees.stream()
                .anyMatch((e)->e.getName().equals("张三"));
        System.out.println(s);

    }
    @Test
    public void show2() {
        //判断是否没有名字是张三  noneMatch
        Boolean s = employees.stream()
                .noneMatch((e)->e.getName().equals("张三"));
        System.out.println(s);

    }
    @Test
    public void show3() {
        //返回第一个元素  findFirst
        Optional s = employees.stream()
                .findFirst();
        System.out.println(s.get());

    }
    @Test
    //返回当前流中的任意元素
    public void show4() {
        //返回第一个元素  findFirst   ///parallelStream并行流
        Optional s = employees.parallelStream()
                .filter((x)->x.getAge()==18)
                .findAny();
        System.out.println(s);
    }
    @Test
    public void show5() {
        //count 获取流中有多好元素
        long s = employees.parallelStream()
                .count();
        System.out.println(s);
    }
    @Test
    public void show6() {
        //count 获取流中有多好元素
        Optional s = employees.parallelStream()
                .max((e1,e2)->Double.compare(e1.getSalary(),e2.getSalary()));
        System.out.println(s.get());
    }

}

规约与收集

package com.lijiawei;

import org.junit.Test;

import javax.swing.text.html.Option;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class TestLamda{
    List<Employees> employees = Arrays.asList(
            new Employees("张三",18,5000),
            new Employees("asd三",18,5000),
            new Employees("张das三",18,5000),
            new Employees("李三",20,10000),
            new Employees("王三",30,15000)
    );
    @Test
    public void show() {
        //规约简单实用
        //指定初始值为0 0+x(1) x=1 y=2  x=3  =4 x=7 y=5..........
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9);
        Integer in =list.stream().reduce(0,(x,y)->x+y);
        System.out.println(in);
    }
    @Test
    public void show1() {
        //mapreduce
        Optional o =employees.stream()
                .map(Employees::getSalary)
                .reduce(Double::sum);
        System.out.println(o.get());
    }
    @Test
    public void show2() {
        //收集 取出集合所有名字并添加到list集合
         List<String> s =employees.stream()
                .map(Employees::getName)
                .collect(Collectors.toList());
        System.out.println(s);
    }
    @Test
    public void show3() {
        //收集 取出集合所有名字并添加到其他集合 比如linkedlist
        LinkedHashSet<String> s =employees.stream()
                .map(Employees::getName)
                .collect(Collectors.toCollection(LinkedHashSet::new));
        System.out.println(s);
    }
}

并行流与顺序流

在这里插入图片描述

package com.lijiawei;

import org.junit.Test;

import java.util.stream.LongStream;

public class TestLamda{

    @Test
    public void show() {
    //0到1千亿累加和
        Long start = System.currentTimeMillis();
        
        LongStream.rangeClosed(0,100000000000L)
                //并行
                .parallel()
                //累加
                .reduce(0,Long::sum);
        Long end = System.currentTimeMillis();
        System.out.println(start-end);
    }
}

接口中的方法

当有类实现这个接口的时候 可以不重写 接口中的默认方法

package com.lijiawei;

public interface My {
    //默认方法
     default public void show(){
        System.out.println("你不好");             
        //静态方法 
      public static void show(){
        System.out.println("你不好");
    }
   
}

注意 1 当 A 类实现一个B接口 并继承一个C类 并且B和C有相同的方法时 优先使用类的 方法

注意2 当A类同时实现了B和C接口 B和C有相同的默认方法 那就必须指定重写方法

package com.lijiawei;

public class Test implements My,Employees{
    @Override
    public String show() {
        return Employees.super.show();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值