您好,欢迎访问三七文档
当前位置:首页 > 临时分类 > JavaLambda表达式学习笔记
JavaLambda表达式是Java8引入的一个新的功能,可以说是模拟函数式编程的一个语法糖,类似于Javascript中的闭包,但又有些不同,主要目的是提供一个函数化的语法来简化我们的编码。Lambda基本语法Lambda的基本结构为(arguments)-body,有如下几种情况:参数类型可推导时,不需要指定类型,如(a)-System.out.println(a)当只有一个参数且类型可推导时,不强制写(),如a-System.out.println(a)参数指定类型时,必须有括号,如(inta)-System.out.println(a)参数可以为空,如()-System.out.println(“hello”)body需要用{}包含语句,当只有一条语句时{}可省略常见的写法如下:(a)-a*a(inta,intb)-a+b(a,b)-{returna-b;}()-System.out.println(Thread.currentThread().getId())函数式接口FunctionalInterface概念JavaLambda表达式以函数式接口为基础。什么是函数式接口(FunctionalInterface)?简单说来就是只有一个方法(函数)的接口,这类接口的目的是为了一个单一的操作,也就相当于一个单一的函数了。常见的接口如:Runnable,Comparator都是函数式接口,并且都标注了注解@FunctionalInterface。举例以Thread为例说明很容易理解。Runnable接口是我们线程编程时常用的一个接口,就包含一个方法voidrun(),这个方法就是线程的运行逻辑。按照以前的语法,我们新建线程一般要用到Runnable的匿名类,如下:newThread(newRunnable(){@Overridepublicvoidrun(){System.out.println(Thread.currentThread().getId());}}).start();如果写多了,是不是很无聊,而基于Lambda的写法则变得简洁明了,如下:newThread(()-System.out.println(Thread.currentThread().getId())).start();注意Thread的参数,Runnable的匿名实现就通过一句就实现了出来,写成下面的更好理解Runnabler=()-System.out.println(Thread.currentThread().getId());newThread(r).start();当然Lambda的目的不仅仅是写起来简洁,更高层次的目的等体会到了再总结。再看一个比较器的例子,按照传统的写法,如下:Integer[]a={1,8,3,9,2,0,5};Arrays.sort(a,newComparatorInteger(){@Overridepublicintcompare(Integero1,Integero2){returno1-o2;}});Lambda表达式写法如下:Integer[]a={1,8,3,9,2,0,5};Arrays.sort(a,(o1,o2)-o1-o2);JDK中的函数式接口为了现有的类库能够直接使用Lambda表达式,Java8以前存在一些接口已经被标注为函数式接口的:java.lang.Runnablejava.util.Comparatorjava.util.concurrent.Callablejava.io.FileFilterjava.security.PrivilegedActionjava.beans.PropertyChangeListenerJava8中更是新增加了一个包java.util.function,带来了常用的函数式接口:FunctionT,R-函数:输入T输出RBiFunctionT,U,R-函数:输入T和U输出R对象PredicateT-断言/判断:输入T输出booleanBiPredicateT,U-断言/判断:输入T和U输出booleanSupplierT-生产者:无输入,输出TConsumerT-消费者:输入T,无输出BiConsumerT,U-消费者:输入T和U无输出UnaryOperatorT-单元运算:输入T输出TBinaryOperatorT-二元运算:输入T和T输出T另外还对基本类型的处理增加了更加具体的函数是接口,包括:BooleanSupplier,DoubleBinaryOperator,DoubleConsumer,DoubleFunctionR,DoublePredicate,DoubleSupplier,DoubleToIntFunction,DoubleToLongFunction,DoubleUnaryOperator,IntBinaryOperator,IntConsumer,IntFunctionR,IntPredicate,IntSupplier,IntToDoubleFunction,IntToLongFunction,IntUnaryOperator,LongBinaryOperator,LongConsumer,LongFunctionR,LongPredicate,LongSupplier,LongToDoubleFunction,LongToIntFunction,LongUnaryOperator,ToDoubleBiFunctionT,U,ToDoubleFunctionT,ToIntBiFunctionT,U,ToIntFunctionT,ToLongBiFunctionT,U,ToLongFunctionT。结合上面的函数式接口,对这些基本类型的函数式接口通过类名就能一眼看出接口的作用。创建函数式接口有时候我们需要自己实现一个函数式接口,做法也很简单,首先你要保证此接口只能有一个函数操作,然后在接口类型上标注注解@FunctionalInterface即可。类型推导类型推导是Lambda表达式的基础,类型推导的过程就是Lambda表达式的编译过程。以下面的代码为例:FunctionString,IntegerstrToInt=str-Integer.parseInt(str);编译期间,我理解的类型推导的过程如下:1.先确定目标类型Function2.Function作为函数式接口,其方法签名为:Integerapply(Stringt)3.检测str-Integer.parseInt(str)是否与方法签名匹配(方法的参数类型、个数、顺序和返回值类型)4.如果不匹配,则报编译错误这里的目标类型是关键,通过目标类型获取方法签名,然后和Lambda表达式做出对比。方法引用方法引用(MethodReference)的基础同样是函数式接口,可以直接作为函数式接口的实现,与Lambda表达式有相同的作用,同样依赖于类型推导。方法引用可以看作是只调用一个方法的Lambda表达式的简化。方法引用的语法为:Type::methodName或者instanceName::methodName,构造函数对应的methodName为new。例如上面曾用到例子:FunctionString,IntegerstrToInt=str-Integer.parseInt(str);对应的方法引用的写法为FunctionString,IntegerstrToInt=Integer::parseInt;根据方法的类型,方法引用主要分为一下几种类型,构造方法引用、静态方法引用、实例上实例方法引用、类型上实例方法引用等构造方法引用语法为:Type::new。如下面的函数为了将字符串转为数组方法引用写法FunctionString,IntegerstrToInt=Integer::new;Lambda写法FunctionString,IntegerstrToInt=str-newInteger(str);传统写法FunctionString,IntegerstrToInt=newFunctionString,Integer(){@OverridepublicIntegerapply(Stringstr){returnnewInteger(str);}};数组构造方法引用语法为:Type[]::new。如下面的函数为了构造一个指定长度的字符串数组方法引用写法FunctionInteger,String[]fixedArray=String[]::new;方法引用写法FunctionInteger,String[]fixedArray=length-newString[length];传统写法FunctionInteger,String[]fixedArray=newFunctionInteger,String[](){@OverridepublicString[]apply(Integerlength){returnnewString[length];}};静态方法引用语法为:Type::new。如下面的函数同样为了将字符串转为数组方法引用写法FunctionString,IntegerstrToInt=Integer::parseInt;Lambda写法FunctionString,IntegerstrToInt=str-Integer.parseInt(str);传统写法FunctionString,IntegerstrToInt=newFunctionString,Integer(){@OverridepublicIntegerapply(Stringstr){returnInteger.parseInt(str);}};实例上实例方法引用语法为:instanceName::methodName。如下面的判断函数用来判断给定的姓名是否在列表中存在ListStringnames=Arrays.asList(newString[]{张三,李四,王五});PredicateStringcheckNameExists=names::contains;System.out.println(checkNameExists.test(张三));System.out.println(checkNameExists.test(张四));类型上实例方法引用语法为:Type::methodName。运行时引用是指上下文中的对象,如下面的函数来返回字符串的长度FunctionString,IntegercalcStrLength=String::length;System.out.println(calcStrLength.apply(张三));ListStringnames=Arrays.asList(newString[]{zhangsan,lisi,wangwu});names.stream().map(String::length).forEach(System.out::println);又比如下面的函数已指定的分隔符分割字符串为数组BiFunctionString,String,String[]split=String::split;String[]names=split.apply(zhangsan,lisi,wangwu,,);System.out.println(Arrays.toString(names));Stream对象概念什么是Stream?这里的Stream不同于io中的InputStream和OutputStream,Stream位于包java.util.stream中,也是java8新加入的,Stream只的是一组支
本文标题:JavaLambda表达式学习笔记
链接地址:https://www.777doc.com/doc-2880368 .html