《33Java GC面试题及答案(第5题).docx》由会员分享,可在线阅读,更多相关《33Java GC面试题及答案(第5题).docx(3页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、ava GC面试题及答案(第5题)如何在lambda表达式中加入Predicate上个例子说到,允许将两个或更多的Predicate合成一个。它提供类似于逻辑操作符AND和OR的方法, 名字叫做and()、or()和xor(),用于将传入filter。方法的条件合并起来。例如,要得到所有以J开始,长度为四个字母的语言,可以定 义两个独立的Predicate例如分别表示每一个条件,然后用Predicateand()方法将它们合并起来。如下所示:PredicatevStringstartsWithJ = (n) -n,startsWith(J);Predicate fourLetterLong =
2、 (n) - n.length() = 4;names.stream().filter(startsWithJ.and(fourLetterLong).forEach(n) -(nName, whichstarts with J and four letter long is:+n);类似地,也可以使用。()和xor()方法。本例着重介绍了如下要点:可按需要将Predicate作为单独条件然后将其合并起来使用。简而言 之,你可以以传统Java命令方式使用Predicate接口,也可以充分利用lambda表达式到达事半功倍的效果。 Java 8中使用lambda表达式的Map和Reduce例如本
3、例介绍最广为人知的函数式编程概念map。它允许你将对象进行转换。例如在本例中,我们将costBeforeTax列表的每个元素转换成 为税后的值。我们将xx*x lambda表达式传到m叩()方法,后者将其应用到流中的每一个元素。然后用幻正北h()”1表元素打印出 来。使用流API的收集器类,可以得到所有含税的开销。有toList()这样的方法将map或任何其他操作的结果合并起来。由于收集器在 流上做终端操作,因此之后便不能重用流了。你甚至可以用流API的reduce。方法将所有数字合成一个,下一个例子将会讲到。List costBeforeTax = Arrays .asList (100,
4、200, 300,100, 500) ;o (Integer cost : costBeforeTax) System.out.printin(price);List costBeforeTax = Arrays.costBeforeTax.stream() .map(cost) -cost +.12*cost) .forEach(System.out:printin);在上面例子中,可以看到m叩 将集合类(例如列表)元素进行转换的。还有一个reduce。函数可以将所有值合并成一个。M叩 和 Reduce操作是函数式编程的核心操作,因为其功能,reduce又被称为折叠操作。另外,reduce并
5、不是一个新的操作,你有可能已经 在使用它。SQL中类似sum。、avg()或者count()的聚集函数,实际上就是reduce操作,因为它们接收多个值并返回一个值。流API 定义的reduceh。函数可以接受lambda表达式,并对所有值进行合并。IntStream这样的类有类似average。、count。、sum()的 内建方法来做reduce操作,也有m叩ToLong。、m叩ToDouble()方法来做转换。这并不会限制你,你可以用内建方法,也可以自 己定义。在这个Java 8的M叩Reduce例如里,我们首先对所有价格应用12%的VAT ,然后用reduceQ方法计算总和。List c
6、ostBeforeTax = Arrays.asList (100, 200, 300, 400, 500);/。)e total = 0; (工ntegNprice = cost + .12 * cost;totaltotal + price;1 ;List costBeforeTax = Arrays . asList (100, 200, 300, 400, 500) ; , bill = costBeforeTax. stream () .map ( (cost). . : 一 . .: 二 .:;.戋冬:心嚼号通过过滤创立一个String列表过滤是Java开发者在大规模集合上的一个常
7、用操作,而现在使用lambda表达式和流API过滤大规模数据集合是惊人的简单。流提供了 一个filter。方法,接受一个Predicate对象,即可以传入一个lambda表达式作为过滤逻辑。下面的例子是用lambda表达式过滤Java 集合,将帮助理解。|Listx.length() 2) .collect(Collectors.toList();System. OL;r . print f (Or i: iu: I l.isiili(、r、d lisisrrList, filterea) ;输出:Original List:abc , , bed , , defg , jk , filter
8、ed list:abc , bed , defg另外,关于filter。方法有个常见误解。在现实生活中,做过滤的时候,通常会丢弃局部,但使用filter。方法那么是获得一个新的列表,且 其每个元素符合过滤原那么。 对列表的每个元素应用函数我们通常需要对列表的每个元素使用某个函数,例如逐一乘以某个数、除以某个数或者做其它操作。这些操作都很适合用map()方法, 可以将转换逻辑以lambda表达式的形式放在map()方法里,就可以对集合的各个元素进行转换了,如下所示。String G7countries=G7.stream().map(x-x.toUpperCase().collect(Colle
9、ctors.joining(,);.;J : . .- i ! ;,,: I , I ; : 1 ;输出:USA , JAPAN , FRANCE , GERMANY , ITALY , U.K. , CANADA复制不同的值,创立一个子列表本例展示了如何利用流的distinct。方法来对集合进行去重用所有不同的数字创立一个正方形列力List工nteger numbers = Arrays.asList(9, 10, 3, 4, 7, 3, 4);Listi*i) . distinct (). collct (Collectors . toList ();SysteE. out .print
10、(Original Lisi : %s, Square Wilhoul duplicalus : %s %n”, numbers, distinct);输出:Original List:9 , 10 , 3,4,7 , 3,4 , Square Without duplicates:81 , 100 , 9 , 16,49计算集合元素的最大值、最小值、总和以及平均值IntStream x LongStream 和DoubleStream 等流的类中,有个非常有用的方法叫做summaryStatistics() o可以返回 IntSummaryStatistics. LongSummarySta
11、tistics DoubleSummaryStatistic s ,描述流中元素的各种摘要娄掂。在本例中,我们 用这个方法来计算列表的最大值和最小值。它也有getSum。和getAverage()方法来获得列表的所有元素的总和及平均值。ysEem. c:二.二 i nt 口(3 ;:.l: ;. g C; it () ) ;System. our . print In (z,/ver;i;(T ;il priiiK- iiuirlirrs : ,z + stat s . cjetxverage () )输出:Highest prime number in List:29Lowest prime
12、 number in List:2 Sum of all prime numbers:129 Average of all prime numbers:12.9Java 8的10个lambda表达式,这对于新手来说是个合适的任务量,你可能需要亲自运行例如程序以便掌握。试着修改要求创立自己 的例子,到达快速学习的目的。补充:从例子中我们可以可以看到,以前写的匿名内部类都用了 lambda表达式代替了。那么,我们简单谈谈lambda表达式&匿名内部类”两者不同:1 .关键字thisQ)匿名内部类中的this代表匿名类(2)Lambda表达式中的this代表lambda表达式的类.编译方式不同匿名内
13、部类中会编译成一个class文件,文件命名方式为:主类+$+(1 , 2 , 3.)(2)Java编译器将lambda表达式编译成类的私有方法。使用了 Java 7的invokedynamic字节码指令来动态绑定这个方法 Java8中的lambda表达式6要点要点1 : lambda表达式的使用位置,预定义使用yFunctional注释的函数式接口,自带一个抽象函数的方法,或者SAM ( Single Abstract Method单个抽象方法)类型。这些称为lambda表达式的目标类型,可以用作返回类型,或lambda目标代码的参数。例如, 假设一个方法接收Runnable. Compara
14、ble或者Callable接口,都有单个抽象方法,可以传入lambda表达式。类似的,如果一个方法 接受声明于包内的接口,例如Predicate. Function. Consumer或Supplier,那么可以向其传lambda表达式。 要点2 : lambda表达式和方法引用,lambda表达式内可以使用方法引用,仅当该方法不修改lambda表达式提供的参数。本例中的 lambda表达式可以换为方法引用,因为这仅是一个参数相同的简单方法调用。list. forEach (System, out: : pr in tin); 仅、川 方法力 山然而,假设对参数有任何修改,那么不能使用方法引用
15、,而需键入完整地lambda表达式,如下所示:list.forEach(* + s + *);事实上,可以省略这里的lambda参数的类型声明,编译器可以从列表的类属性推测出来。要点3 : lambda表达式内部引用资源,lambda内部可以使用静态、非静态和局部变量,这称为lambda内的变量捕获。要点4 : lambda表达式也成闭包,Lambda表达式在Java中又称为闭包或匿名函数,所以如果有同事把它叫闭包的时候,不用惊讶。 要点5 : lambda表达式的编译方式,Lambda方法在编译器内部被翻译成私有方法,并派发invokedynamic字节码指令来进行调 用。可以使用JDK中的
16、javap工具来反编译class文件。使用javap -p或jav叩-c-v命令来看一看lambda表达式生成的字 节码。:“Il java, lang. Object lambda$() (java. lang. String);要点6 : lambda表达式的限制,lambda表达式有个限制,那就是只能引用final或final局部变量,这就是说不能在lambda内 部修改定义在域外的变量。List primes = Arrays. asList ( 八),工 nteger2, 3,5,7); nl factor = 2;primes.forEach(element - factor+; );Error:Compile time error:local variables referenced from a lambda expression must be final or effectively final 另外,只是访问它而不作修改是可以的,如下所示:List工nteger primes = Arrays.asList (工nteger2, 3,5,7); nl factor = 2;输出:461014因此,它看起来更像不可变闭包,类似于Python。