lambdas for_Java 8发布了! — Lambdas教程

lambdas for

为了庆祝几分钟前发布的Java 8的发布,我正在发布Java 8 Lambdas教程的草稿版本。 这是学习Streams API的一种很好的可视化方式,从第一天开始,它将帮助您开始在自己的应用程序中使用lambda。本文计划在下一期Java Magazine发行中发表,因此,请期盼最终的。版本,如果它们在出版截止日期之前,我会尽力纳入评论和反馈。

图片1

玛丽有个小拉姆达

自从Java 5中的泛型发布以来,Java Lambda是进入Java语言最有影响力的功能。它从根本上改变了编程模型,允许开发一种功能样式,并支持有效的代码并行化以利用多核系统。 尽管作为Java开发人员,您首先会注意到使用Java 8中启用了lambda的新API获得的生产力提高。

在本文中,我们将通过使用JavaFX编写的复古游戏向您介绍用于处理集合和数据的新Streams API。 该游戏既是一个从头开始编写的简单Java 8应用程序,用于展示lambda的最佳实践,又是使用Streams API进行编程的直观指南。 但是,我们将首先通过介绍lambdas语言更改来奠定基础。

Lambdas简介

要使用lambda,必须使用最新的Java SDK(8或更高版本),并在编译时将语言级别设置为Java 8。 您可以从以下位置下载最新的Java SDK版本:

  • http://www.oracle.com/technetwork/java/javase/downloads/index.html

使用支持新语法的IDE时,开发lambda变得容易得多。 大多数Java IDE已更新为具有lambdas支持,并将帮助您进行lambdas的实时错误报告和代码完成。 NetBeans和IntelliJ值得一提,因为它们在Java 8发行之时即刻提供了最佳的lambda支持,并且都可以与我们在此演示的示例很好地配合使用。

为了演示新的lambdas功能是如何工作的,以下是一小段代码,它循环访问形状列表并将蓝色的形状更改为红色:

for (Shape s : shapes) {if (s.getColor() == BLUE)s.setColor(RED);
}

在Java 8中,您可以使用如下的forEach和lambda表达式来重写相同的代码:

shapes.forEach(s -> {if (s.getColor() == BLUE)s.setColor(RED);
});

lambda表单在Collection接口上使用了一个称为forEach的新方法,该方法采用lambda表达式并对所有包含的元素求值。 整个Java核心类都进行了类似的API增强,以简化lambda表达式的使用。

您可能遇到的一个相关问题是Java团队如何在不破坏向后兼容性的情况下向接口添加新方法。 例如,如果您具有实现Collection接口的代码,但未定义forEach方法,那么升级到Java 8不会破坏您的实现吗? 幸运的是,另一个称为扩展方法的功能解决了Java 8中的此问题。下面的代码清单显示了Collection接口上的forEach实现:

interface Collection<T> {default void forEach(Block<T> action) {Objects.requireNonNull(action);for (T t : this)action.apply(t);}// Rest of Collection methods…
}

注意新的默认关键字,它指示该方法后面将是默认实现。 子类可以自由创建自己的方法实现,但是如果未定义,则子类将获得与接口中定义的相同的标准行为。 这允许将新方法添加到核心Java类以及您自己的库和项目中的现有接口。

实际的lambda语法非常简单……以完整的形式在左侧提供类型和参数,在中间加一个破折号,大于号[->],并在其后加上大括号的方法主体:

(int a, int b) -> { return a + b; }

在函数返回值的情况下,可以通过删除花括号,return关键字和分号来简化此操作:

(a, b) -> a + b

此外,在只有一个参数的情况下,您可以省略括号:

a -> a * a

最后,如果没有参数,则只需将括号留空,这对于替换Runnable实现或其他无参数方法很常见:

() -> { System.out.println("done"); }

除了基本语法外,还有一种特殊的快捷方式语法称为“方法引用”,它使您可以快速创建将单个方法引用为实现的lambda表达式。 下表总结了不同类型的方法引用以及等效的长格式lambda语法。

方法参考 等效λ
对象:: toString obj-> Objects.toString(obj) 静态方法参考
对象:: toString obj-> obj.toString() 会员方法参考
obj :: toString ()-> obj.toString() 对象方法参考
对象::新 ()->新的Object() 构造方法参考

使用新的lambdas方法时,最重要的最后一个概念是创建允许您接受lambda表达式的接口。 为此,具有一个显式声明的抽象方法的任何接口都可以用于接受lambda表达式,因此被称为功能接口。

为了方便起见,他们引入了新的FunctionalInterface批注,可以选择使用该批注来标记接口,以便在检查以确保您的接口满足单个显式声明的抽象方法要求时从编译器获取帮助:

@FunctionalInterface
interface Sum {int add(int a, int b);
}

这是推荐的最佳实践,因为它会在功能接口的定义中遇到一些极端情况,例如包含默认方法,这些默认方法使您可以在功能接口上定义多个方法,因为它们不是抽象的,并且不计入单一抽象方法要求。

现在您已经对lambda语法有了基本的了解,是时候探索流API并在一个可视示例的上下文中展示lambda的功能了。

Lambdas复古游戏

玛丽有点lambda

谁的羊毛洁白如雪

玛丽去过的任何地方

Lambda一定会去!

图片2 如今,视频游戏都是关于高分辨率3D图形,电影品质的剪切场景以及从新手到和平主义者的难度级别。 但是,在游戏的美好时光中,我们只有精灵……可爱,像素化的小人物跳舞和RPG穿越精心设计的疯狂难度关卡。

基于Sprite的图形也很容易编程,从而使我们可以用不到400行代码构建完整的动画系统。 完整的应用程序代码在GitHub的以下位置:

  • https://github.com/steveonjava/ MaryHadALittleLambda

对于游戏中使用的所有图形,图像以标准的3×4平铺格式进行布局,如Mary的相邻Sprite表中所示。 (当然)使用lambda完成了动画精灵的代码,只需在平铺的图像周围移动视口即可生成3帧的行走动画[水平]并更改角色朝向的方向[垂直]。

ChangeListener<Object> updateImage =(ov, o, o2) -> imageView.setViewport(new Rectangle2D(frame.get() * spriteWidth,direction.get().getOffset() * spriteHeight,spriteWidth, spriteHeight));
direction.addListener(updateImage);
frame.addListener(updateImage);

为背景添加静态图像,并添加一些关键事件侦听器以在输入时移动角色,您便拥有了经典RPG游戏的基础知识!

图片3

产生流

有几种创建新Java 8 Stream的方法。 最简单的方法是从您选择的集合开始,然后简单地调用stream()或parallelStream()方法来获取Stream对象,如以下代码片段所示:

anyCollection.stream();

您还可以使用Stream类上的静态帮助器方法从一组已知的对象返回流。 例如,要获取包含一组字符串的流,可以使用以下代码:

Stream.of("bananas", "oranges", "apples");

同样,您可以使用Stream数字子类(例如IntStream)取回生成的一系列数字:

IntStream.range(0, 50)

但是,生成新系列最有趣的方法是在Stream类上使用generate和iterate方法。 这些使您可以使用lambda创建新的对象流,该lambda被调用以返回新对象。 迭代方法特别有趣,因为它将先前创建的对象传递给lambda。 这使您可以为每个调用返回一个不同的对象,例如,迭代地返回彩虹中的所有颜色:

Stream.iterate(Color.RED,c -> Color.hsb(c.getHue() + .1, c.getSaturation(),c.getBrightness()));

为了演示它在视觉上是如何工作的,我们将在踩到绵羊的应用程序中添加一个新元素。

新的Barn类的代码如下:

public static class Barn extends MapObject {static final Image BARN = loadImage("images/barn.png");public Barn(Main.Location loc) {super(BARN, loc);}@Overridepublic void visit(Shepherd s) {SpriteView tail = s.getAnimals().isEmpty() ?s : s.getAnimals().get(s.getAnimals().size() - 1);Stream.iterate(tail, SpriteView.Lamb::new).skip(1).limit(7).forEach(s.getAnimals()::add);}
}

这段代码指定了用于基于Sprite的图形的图像,该图像被传递给超级构造函数,并实现了一个visit方法,该方法具有当Mary踏上谷仓时将被执行的逻辑。

visit方法中的第一个语句只是从Mary后面的动物列表中获取最后一个元素,如果还没有动物,则返回她。 然后将其用作iterate方法的种子,该方法将被传递给Lamb构造函数以进行lambda的首次调用。 然后,由此生成的羔羊将被传递给Lamb构造函数以进行第二次调用,并且此过程将连续重复。

结果流包括种子,因此我们可以使用skip函数从流中删除该种子,并且从理论上讲它是无限的。 由于流是惰性的,因此在添加终端操作之前,我们不必担心会创建对象,但是固定流长度的一种简单方法是使用limit函数,我们将参数7设置为跟随玛丽生出七只羊。 最后一步是添加将使用该流的终端操作。 在这种情况下,我们将使用forEach函数,并将lambda表达式设置为对动物列表中add方法的方法引用。 执行此lambda的结果是接连跟随Mary的七个羔羊:

图片4

我们要添加到游戏中的下一个元素是彩虹,它将演示Streams API中的过滤。 过滤器函数的工作方式是采用谓词lambda,该谓词对流中的每个元素求值为true或false。 结果流包含谓词lambda评估为true的所有元素。

对于彩虹的逻辑,我们将执行一个过滤器,该过滤器返回流中每 4 动物,并应用JavaFX ColorAdjust函数来改变色相以匹配传入的颜色。 对于白色,我们使用null(无颜色偏移)。 以下代码是Rainbow MapObject的visit方法的实现:

s.getAnimals().stream().filter(a -> a.getNumber() % 4 == 1).forEach(a -> a.setColor(null));
s.getAnimals().stream().filter(a -> a.getNumber() % 4 == 2).forEach(a -> a.setColor(Color.YELLOW));
s.getAnimals().stream().filter(a -> a.getNumber() % 4 == 3).forEach(a -> a.setColor(Color.CYAN));
s.getAnimals().stream().filter(a -> a.getNumber() % 4 == 0).forEach(a -> a.setColor(Color.GREEN));

当玛丽踩到彩虹时,所有的羔羊都会根据您指定的颜色值着色:

图片5

“ Lamb” da问题1:如果您在参观彩虹后踏上谷仓会怎样?

使用过滤的另一种方法是利用添加到Collection API的新方法来接受谓词lambda。 其中包括removeIf,它过滤掉与给定谓词不匹配的所有元素,并进行过滤(位于ObservableList上)并返回只包含与谓词匹配的项的FilteredList。

我们将使用它们来实现Church对象,该对象将过滤“纯”动物。 教会职员会煮熟任何白色的动物,以喂养有需要的人。 这包括增加标牌上“已送餐”的计数器,并从列表中删除“纯”动物。 教会拜访方法的代码如下所示。

Predicate<SpriteView> pure =a -> a.getColor() == null;mealsServed.set(mealsServed.get() +s.getAnimals().filtered(pure).size()
);s.getAnimals().removeIf(pure);

在以下屏幕截图中,您可以看到连续踩彩虹和教堂的结果。

图片6

“ Lamb” da问题2:是否可以使用教堂清除所有已经着色的动物?

Streams API中最强大的操作可能是地图功能。 这使您可以将流中的所有元素从一种对象类型转换为另一种对象,并在此过程中执行强大的转换。 我们将用它来实现鸡舍,所有跟随玛丽的动物都将被转换成卵。

对于鸡舍,我有两种访问方法的实现。 第一个使用带有lambda表达式的单个map操作用鸡蛋替换流元素,如下所示:

// single map:
s.getAnimals().setAll(s.getAnimals().stream().map(sv -> new Eggs(sv.getFollowing())
).collect(Collectors.toList()));

第二种实现使用方法引用和一组映射操作链来首先将流转换为动物所跟随的流,然后调用构造函数方法引用来创建鸡蛋,并将以下信息传递给构造函数参数:

// or a double map:
s.getAnimals().setAll(s.getAnimals().stream().parallel().map(SpriteView::getFollowing).map(Eggs::new).collect(Collectors.toList())
);

这两个代码片段的行为和执行相似,因为流API被设计为惰性的,并且仅在调用终端操作(例如collect)时评估流。 因此,它主要是您更喜欢使用的样式问题。 使用新的鸡舍MapObject运行该程序,可以让您从羔羊生成鸡蛋,如下图所示:

图片7

问题3:如果您将彩色的羊羔送到鸡舍,鸡蛋是什么颜色?

请注意,每个鸡蛋精灵包含三个小弹跳鸡蛋。 如果我们能把这些家伙孵化成鸡,那不是很好吗?

要孵化这些鸡蛋,我们将为巢添加一个新的MapObject,其中使用以下孵化方法将这些鸡蛋孵化成三只鸡的组:

public static Stream<SpriteView> hatch(SpriteView sv) {if (!(sv instanceof Eggs)) {return Stream.of(sv);}return Stream.iterate(sv, Chicken::new).skip(1).limit(3);
}

请注意,此方法返回一个对象流,这意味着如果我们使用常规映射操作,我们将返回一个流流。 为了将Stream扁平化为单个鸡列表,我们可以改用flatMap,它将既使用lambda函数映射流,又将嵌套的Stream折叠为单个对象列表。 使用flatMap的嵌套访问功能的实现如下所示:

s.getAnimals().setAll(s.getAnimals().stream().parallel().flatMap(SpriteView.Eggs::hatch).collect(Collectors.toList())
);

现在,将鸡蛋放到巢中后,您将得到鸡的爆炸,如以下屏幕截图所示:

图片8

问题4:在游戏内存不足之前,您可以添加大约几只动物?

我们将添加的最后一个元素是一只狐狸,以演示如何减少流。 为此,我们将首先根据动物的规模将流映射到整数列表,然后使用sum方法引用将其减少为单个值。 reduce函数需要一个种子值(我们将使用0作为其值),以及一个可以将两个元素简化为单个结果的函数。 该lambda将递归应用于流中的所有元素,直到得到单个值,该值将是所有动物比例的总和。

Double mealSize = shepherd.getAnimals().stream().map(SpriteView::getScaleX).reduce(0.0, Double::sum);setScaleX(getScaleX() + mealSize * .2);
setScaleY(getScaleY() + mealSize * .2);
shepherd.getAnimals().clear();

然后,我们将总和(存储到名为mealSize的变量中)并使用该总和按比例拉伸狐狸。 您可以在下图中看到为狐狸吃一顿美味的食物的结果:

图片9

问题5:您如何更改Fox的代码以使其在进食时变胖?

在本文中,我们介绍了基本的lambda语法,包括方法引用,扩展方法和功能接口。 然后,我们在Streams API中进行了详细介绍,展示了一些常见的操作,例如迭代,过滤,映射,flatMap和reduce。 如您所见,Java 8 lambda极大地改变了编程模型,使您可以编写更简单,更精美的代码,并为诸如Streams之类的新的强大API提供了可能性。 现在是时候在您自己的开发中开始利用这些功能了。

翻译自: https://www.javacodegeeks.com/2014/03/java-8-released-lambdas-tutorial.html

lambdas for

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/343200.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

为什么工业交换机需要CE认证

工业交换机的使用越来越广&#xff0c;不管是我们国内的市场还是国外的市场&#xff0c;都大量的存在着&#xff0c;也成为国际之间的贸易&#xff0c;在出口到国外的工业交换机&#xff0c;在进入到国外时交换机是必须要有CE认证标记的&#xff0c;它是进入到市场上最低标准。…

lora技术在无线抄表行业应用

随着社会不断的发展&#xff0c;几乎家家户户都已经安装了家庭用电&#xff0c;但是大量的用户也造成了管理不便的麻烦&#xff0c;传统的抄表方式往往需要投入大量的人工和时间成本&#xff0c;所以现在急需一种自动化、方便、简单的抄表方式。 传统的人工抄表方式不但效率低下…

linux执行脚本n,Linux执行sh脚本空白

笔者在初步研究了Windows的SYSTEM.INI后发现&#xff0c;通过VB的多媒体控件MCI.VBX可以打开MPEG压缩文件(如VCD2.0版的.DAT文件)"Err.ClearEndIfNext取得当前Windows序列号函数FunctionGetWindowsSN()ConstHKEY_LOCAL_MACHINE&H80000002strKeyPath"SOFTWARE\Mic…

这四种攻击单片机的主要技术你了解多少?

本文来自 成都亿佰特  为了防止未经授权访问或拷贝单片机的机内程序&#xff0c;大部分单片机都带有加密锁定位或者加密字节&#xff0c;以保护片内程序。如果在编程时加密锁定位被使能&#xff08;锁定&#xff09;&#xff0c;就无法用普通编程器直接读取单片机内的程序&am…

以太网交换机的概念,网络接口和主要特点

以太网交换机这个名词相信很多人都听过吧&#xff0c;那么大家知道什么是以太网交换机吗&#xff1f;关于以太网交换机大家又知道多少呢&#xff0c;接下来就由飞畅科技的小编来给大家详细介绍一下以太网交换机的基本概念以及网络接口方式和主要特点&#xff0c;一起来看看吧。…

智能插座常用的两种通信协议——WIFI和ZigBee

随着科技技术的不断发展&#xff0c;智能家居的概念不断的深入人心&#xff0c;人们利用智慧不断开创新的生活。比尔盖茨是第一个智能家居的使用者&#xff0c;也许很多人都会认为智能家居是高端的设备&#xff0c;只有想比尔盖茨那样的有钱人才能够使用&#xff0c;其实不然&a…

以太网交换机坏了,能否用光纤收发器来替代?

近期&#xff0c;有朋友在后台咨询我们&#xff1a;现有的以太网交换机坏了&#xff0c;能否用光纤收发器来替代&#xff1f;相信很多朋友都有过这样的疑问&#xff0c;答案肯定是否&#xff0c;我们不建议大家用光纤收发器替代以太网交换机来使用&#xff01;因为以太网交换机…

javafx canvas_JavaFX技巧1:可调整大小的Canvas

javafx canvas在使用FlexGanttFX时&#xff0c;我不得不处理很多JavaFX Canvas节点。 我正在使用它在时间轴上呈现活动。 甘特图中的每一行都是一个Canvas节点。 用户可以选择单独调整每行的大小。 因此&#xff0c;我不得不找出调整画布大小的最佳方法&#xff0c;这种现成的方…

工业级4G无线路由器有哪些特点如何选择

工业级4G无线路由器因其具性能高。传输速度快且数据处理能力强等这些比较突出的特点&#xff0c;在电力、交通、金融、工控等各大行业中都有着广泛的应用&#xff0c;并受到了人们高度推崇和青睐。那么&#xff0c;工业级4G无线路由器有那些的特点受到消费者的青睐呢&#xff1…

3分钟看懂工业交换机EMS试验和高低温测试

机子行不行&#xff0c;全靠试验评。上期IES6312的开箱视频中提到&#xff0c;我们该如何确定产品的稳定和可靠性&#xff0c;本期就是12口全千兆二层网管型工业以太网交换机系列测试视频&#xff0c;全视频一共做了4项试验&#xff1a;高低温测试、EMS试验三个&#xff08;静电…

NB-IoTDTU对比于3G/4G DTU的区别和优势

作为物联网领域的新兴技术&#xff0c;低功耗广域网技术NB-IOT自2016年问世以来&#xff0c;围绕着其开展的技术研发和市场布局也在高速的发展中。而曾占据历史舞台的传统的基于移动网络的3G/4G DTU也依然活跃在人们的眼中&#xff0c;那么新兴的NB-IOT DTU和3G/4G DTU有哪些区…

linux 中文ssid 显示,无法连接中文 SSID 的 Wi-Fi?简单几步就搞定!

忙里偷闲&#xff0c;今天把树莓派拿出来准备搞点事情&#xff0c;但发现宿舍的中文 SSID 无法被树莓派正确识别&#xff0c;变成了一堆 16 进制数&#xff1a;虽然如此&#xff0c;但我猜测只是显示上的问题&#xff0c;猜得出是哪个 Wi-Fi&#xff0c;剩下应该就没什么问题了…

安防专用交换机的应用介绍

安防专用交换机作为特别类型的交换机,最近几年&#xff0c;由于监控行业的迅速普及与应用&#xff0c;安防专用交换机开始迅速在安防领域内普及&#xff0c;使用数量急剧增加&#xff0c;为安防行业的发展&#xff0c;提供了强有力的源动力。那么&#xff0c;安防工业交换机的应…

ZigBee技术的应用和优势

ZigBee一词源自蜜蜂群在发现划分位置时&#xff0c;通过跳ZigZag形舞蹈来告知同伴&#xff0c;来达到交换信息的目的。可以说是一种小的低信息量的“无线"通信方式&#xff0c;人们也就借此称呼一种专注于低功耗&#xff0c;低成本、低复杂度、低速率的、低速率的近程无线…

linux 下 storm环境搭建,Storm在Ubuntu环境下的单机部署

Storm在Ubuntu环境下的单机部署目录查看Ubuntu安装JDK安装Pythod安装Zookeeper安装ZeroMQ安装Jzmp安装Storm查看Ubuntu是32位还是64uname -a返回结果 > SMP Fri Feb 22 00:31:26 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux,可知Ubuntu为64位安装JDK#下载64位的JDKwget http:…

物联网中常见的传感器类型

物联网&#xff08;IOT&#xff09;是最近几年来最热门的技术流行语&#xff0c;它指的是&#xff1a;在收集、共享和分析数据&#xff0c;并从中创造价值。但如果没有准确数据&#xff0c;物联网也将成为一对无用的技术&#xff0c;因此&#xff0c;传感器和执行器的重要性使其…

杭州飞畅告诉你工业环网交换机到底是什么?

环网交换机是一种特殊的交换机&#xff0c;因为主流的环网交换机均为工业交换机&#xff0c;因此一般可以将其称为工业级环网交换机。那么&#xff0c;工业环网交换机到底是什么呢&#xff1f;接下来我们就跟随飞畅科技的小编一起来详细了解下吧&#xff01; 环网&#xff0c;…

工业级以太网交换机具有哪些优越特性

与商用交换机相比&#xff0c;工业交换机在性能上要稳定&#xff0c;需要耐受严苛的工作环境。工业交换机产品采用宽温设计&#xff0c;防护等级不低于IP30&#xff0c;支持标准和私有的环网冗余协议。那么&#xff0c;工业级以太网交换机具有哪些优越特性呢?接下来我们就跟随…

工业物联网的应用领域和方向

从一定的程度上来说&#xff0c;物联网可以说是个“旧瓶装新酒”的概念&#xff0c;提出物联网——IoT&#xff08;Internet of things&#xff09;这个概念的确算是一种创新&#xff0c;但是也要把这个创新和传统的M2M——机器互联&#xff08;machine to machine&#xff09;…

物联网控制系统

物联网的发展和使用是跨时代的改变&#xff0c;在当今我们这个科技高速发展的时代&#xff0c;智能控制就是改善我们生活水平的主要方式。 随着物联网概念的深入&#xff0c;从智能路灯、智能家居到智慧农业、工业互联网&#xff0c;物联网不断的渗透到了各行各业当中&#xff…