java8初体验《Lambda表达式》(一)

目录

java8新特性

一、主要内容

二、java8新特性简介

三、具体介绍

3.1 Lambda表达式

3.1.1简单的语法比较

3.2具体语法

3.3 什么是函数式接口

3.3.1 自定义函数式接口

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

3.3.2.1 Consumer

3.3.2.2 Supplier

3.3.2.3 Function(使用比较多)

3.4 方法引用与构造器引用

3.4.1 demo演示

3.4.1.1 对象引用::实例方法

3.4.1.2类:: 静态方法

3.4.1.3 类::实例方法

3.4.2构造器引用


java8新特性


个人的感受:虽然现在学习java8有点晚,但是现在还不去学,那不是更晚了?在这个it界,如果不去学习,那就只能被淘汰,学总比不学好,总之:不知道  <   知道(听说过)  <   了解(会使用一点) <   正常使用(基本的使用没有问题) <  精通我们至少要能达到正常使用。虽然现在的一些项目可能还在用之前的jdk 版本,万一哪天要用了呢?多学习总是没错的


一、主要内容

  • 1. Lambda 表达式
  • 2. 函数式接口
  • 3. 方法引用与构造器引用
  • 4. Stream API
  • 5. 接口中的默认方法与静态方法
  • 6. 新时间日期 API
  • 7. 其他新特性

二、java8新特性简介

  • 速度更快
  • 代码更少(增加了新的语法 Lambda 表达式
  • 强大的 Stream API
  • 便于并行
  • 最大化减少空指针异常 Optional

核心就是标红的 两个

三、具体介绍

3.1 Lambda表达式

   为啥要使用这个?答:方便,快捷。

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

3.1.1简单的语法比较

    既然是接口,那就从接口出发

 public void test1(){
        // 匿名内部类转换

        // 匿名内部类
        Runnable run = new Runnable() {
            @Override
            public void run() {
                System.out.println("this is one ");
            }
        } ;

        //lambda表达式 无参数 无返回值
        Runnable runL =  ()->{ System.out.println("this is one ");} ;
    }

没有实际作用?看下面这个

public void test2(){
        // 匿名内部类转换
        TreeSet<Integer> treeSet = new TreeSet<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1,o2);
            }
        });

        // 简单应用 
        TreeSet<Integer> treeSet2 = new TreeSet<>(
                (o1,o2)->Integer.compare(o1,o2)
        );
    }

3.2具体语法

敲黑板讲解:

   Lambda 表达式在Java 语言中引入了一个新的语法元 素和操作符。这个操作符为 “->” , 该操作符被称 为 Lambda 操作符或剪头操作符。它将 Lambda 分为 两个部分:

  •   左侧:指定了 Lambda 表达式需要的所有参数
  •   右侧:指定了 Lambda 体,即 Lambda 表达式要执行 的功能。

3.2.1具体实现

语法格式一:无参,无返回值,Lambda 体只需一条

//lambda表达式 无参数 无返回值
        Runnable runL =  ()->{ System.out.println("this is one ");} ;

语句语法格式二:Lambda 一个参数语法

  // 有一个参数 无返回值
        Consumer<String> con = (args)-> System.out.println(args) ;

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

 // 有一个参数 无返回值
        Consumer<String> con2 =  args -> System.out.println(args) ;

格式四:Lambda 需要两个参数,并且有返回值

 // 有两个参数 并且有返回值 ,
        BinaryOperator<Long> fun = (x, y)->{ return x+y} ;

语法格式五:当Lambda 体只有一条语句时,return 与大括号可以省

// 有两个参数 并且有返回值 ,
        BinaryOperator<Long> fun = (x, y)->{   x+y} ;

语法格式六:类型可以省略

// 简化一 有两个参数 并且有返回值 ,
        BinaryOperator<Long> fun = ( Long x, Long y)->{ return   x+y} ;
// 简化三 有两个参数 并且有返回值 ,如果lambda体中的数据只有一条语句,可以不用return ,也可以不用大括号
        BinaryOperator<Long> fun3 = (  x,  y)->   x+y  ;

为啥类型可以省略:

 Lambda 表达式中的参数类型都是由编译器推断 得出的。Lambda 表达式中无需指定类型,程序依然可 以编译,这是因为 javac 根据程序的上下文,在后台 推断出了参数的类型。Lambda 表达式的类型依赖于上 下文环境,是由编译器推断出来的。这就是所谓的 “类型推断

  lambda基础语法已经介绍完毕,下面介绍实际使用


使用之前我们需要知道一个知识点

3.3 什么是函数式接口

  • 只包含一个抽象方法的接口,称为函数式接口。 
  • 你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda 表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方法上进行声明)。
  • 我们可以在任意函数式接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。

3.3.1 自定义函数式接口

/**
 * @author yx start
 * 1.只包含一个抽象方法的接口
 * 2.@FunctionalInterface 注解,
 * 这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包
 * 含一条声明
 * @create 2019/4/21,12:32
 */
@FunctionalInterface
public interface MyInterface<T> {
    public  T getValue(T t) ;
}
/**
     * 进行调用
     * @param args
     */
    public static void main(String[] args) {
        test4();
    }

    /**
     * 将接口传递给自定义接口
     *  str -> str.toUpperCase() 就是对MyInterface 接口的实现。 
     */
    public static void test4(){
        String strRes = testMyFun( str -> str.toUpperCase(), "abdced");
        System.out.println(strRes);
    }

    /**
     * 定义一个使用,传值自定义的接口(可以是)
     * @param mf
     * @param str
     * @return
     */
    private static  String testMyFun(MyInterface<String> mf ,String str) {
            return mf.getValue(str) ;
    }

 lambda 对接口实现,然后lambda体的实现可以自定义,不用像之前的那么写的死死的

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

 我们不可能每次都是自己定义接口,太麻烦了。java有内置的。

* Consumer<T> 消费型接口  有参数 T,无返回
* Supplier<T> 供给型接口  无参数,有返回 T
* Function<T, R>函数型接口有参数 T ,有返回 R
* Predicate<T> 断定型接口   有参数T ,有返回Boolean

3.3.2.1 Consumer

Consumer<T> 消费型接口  有参数 T,无返回
 @Test
    public void TestconSumer(){
        consumer(str->System.out.println(str.toLowerCase()),"MY_CONSOUMER ");
    }

    /**
     * test 消费型接口
     * @param con
     * @param str
     */
    public void consumer(Consumer<String> con, String str){
         con.accept(str);
    }

3.3.2.2 Supplier

Supplier<T> 
Supplier<T> 供给型接口  无参数,有返回 T

 需求:根据指定的数字,随机生成数据添加到集合中

 // Supplier<T> 供给型接口  无参数,有返回 T

    @Test
    public void testSupp(){
        List<Integer> list = getList(5, () -> (int) (Math.random() * 100));
        list.forEach(System.out::println) ;
    }
    /***
     *Supplier<T> 供给型接口  无参数,有返回 T
     * 获取10个随机整数,添加到集合中
     *
     * @param num
     * @param supplier
     * @return
     */
    public List<Integer> getList(int num, Supplier<Integer> supplier){
        List list = new ArrayList( );
        for (int i = 0; i < num; i++) {
            System.out.println(supplier.get());
            list.add( supplier.get());
        }
        return list ;
    }

3.3.2.3 Function(使用比较多)

Function<T, R>函数型接口有参数 T ,有返回 R

简单的需求:针对参数字符串的变大写返回

 //Function<T, R>函数型接口有参数 T ,有返回 R  =====================
    @Test
    public void  testFunction(){
        String this_is_test_fun = getString(str -> str.toUpperCase(), "this is test Fun");
        System.out.println( this_is_test_fun);
     }

    public String getString(Function<String,String> fun,String  str ){
        return fun.apply(str) ;
    }

3.3.2.4 Predicate

Predicate<T> 断定型接口   有参数T ,有返回Boolean

需求:将list<String> str 中符合要求的过滤  要求:是否包含  "yx" 字符串

 // Predicate<T> 断定型接口   有参数T ,有返回Boolean
    @Test
    public void  testPre(){
        List<String> stringres = new ArrayList<>();
        List<String> strings = Arrays.asList("yxa,asd,yasdsad,yxja,sadasd".split(","));
        for (int i = 0; i <strings.size() ; i++) {
            String tempStr =  strings.get(i) ;
            if(filterYxStr(str->str.contains("yx"),tempStr)){
                stringres.add(tempStr) ;
            }
        }
        stringres.forEach(System.out::println);
    }

    public boolean filterYxStr(Predicate<String> predicate, String str){
      return   predicate.test(str);
    }

以上都是简单的demo 演示、

还有其他的,这些核心的肯定有相应的子类可以做到

内置核心接口完。。


3.4 方法引用与构造器引用

    干嘛的?这又是啥????

答:  别慌,方便我们稍微简单一点的。比如我们要做的lambda实现重,已经有方法已经实现了。我们就可以方法引用了。

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

方法引用语法:使用操作符 “::” 将方法名和对象或类的名字分隔开来。 

3.4.1 demo演示

使用场景:

  •  对象 :: 实例方法
  •  类 :: 静态方法
  •  类 :: 实例方法

3.4.1.1 对象引用::实例方法

public void testRef(){
        PrintStream print = System.out ;
        // 之前的做法: 
        Consumer<String> sup = (str)-> print.println("lambda"+str) ;
        
        // 方法引用,因为 PrintStream 有了 println 方法,所以就直接使用,括号都不用
        Consumer<String> supRef = print::println; 
    }

3.4.1.2类:: 静态方法

 // 类:: 静态方法 注意:参数要一致(lambda调用的方法体的返回值类型要和函数类别的返回值类型一致)
        Comparator<Integer> com = (x,y)->Integer.compare(x,y) ;
        Comparator<Integer> com2 = Integer::compare;

3.4.1.3 类::实例方法

 // 类:: 实例方法  使用条件: 两个 参数,第一个参数是调用者,第二个是调用的参数时
        BiPredicate<String,String> bp = (x,y)->x.equals(y);
        BiPredicate<String,String> bp2 = String::equals;

3.4.2构造器引用

格式: ClassName::new 

与函数式接口相结合,自动与函数式接口中方法兼容。 可以把构造器引用赋值给定义的方法,与构造器参数 列表要与接口中抽象方法的参数列表一致!

 // 构造器引用
        Supplier<Person> supplier = ()->new Person() ;
        Supplier<Person> supplier2 = Person::new ;

        // 如果多个构造器 调用的构造器根据参数的返回值决定
        Function<String,Person> fun = str->new Person(str) ;
        Function<String,Person> fun2 = Person::new;
        Person person = fun2.apply("张飞");

 public class  Person{
        private String name ;
        private String address ;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getAddress() {
            return address;
        }

        public void setAddress(String address) {
            this.address = address;
        }

        public Person() {
        }

        public Person(String name, String address) {
            this.name = name;
            this.address = address;
        }

        public Person(String name) {
            this.name = name;
        }
    }

强大的 Stream API 下篇接上 https://blog.csdn.net/yangxin_blog/article/details/89432653

发布了107 篇原创文章 · 获赞 30 · 访问量 33万+

猜你喜欢

转载自blog.csdn.net/yangxin_blog/article/details/89429874