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;所以现在急需一种自动化、方便、简单的抄表方式。 传统的人工抄表方式不但效率低下…

【渝粤教育】国家开放大学2018年秋季 2726T畜禽生产概论 参考试题

试卷代号&#xff1a;2746 农科化学基础知识 试题&#xff08;开卷&#xff09; 2019年1月 注意事项 一、将你的学号、姓名及分校&#xff08;工作站&#xff09;名称填写在答题纸的规定栏内。考试结束后&#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…

【渝粤教育】国家开放大学2018年秋季 3781-22T燃气燃烧技术与设备 参考试题

试卷代号&#xff1a;3895 管理英语1 试题 2019年1月 注 意 事 项 一、将你的学号、姓名及分校&#xff08;工作站&#xff09;名称填写在答题纸的规定栏内。考试结束后&#xff0c;把试卷和答题纸放在桌上。试卷和答题纸均不得带出考场。监考人收完考卷和答题纸后才可离开考场…

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

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

将旧对象装箱可自动关闭

从Java 7开始&#xff0c;我们可以使用try-with-resources并自动关闭任何实现Autocloseable接口的对象。 如果资源是 Autocloseable 。 一些类需要一些总结&#xff0c;但不是Autocloseable 。 这些主要是某些遗留框架中的旧类&#xff0c;仍然妨碍我们前进。 没有人再使用Stru…

【渝粤教育】国家开放大学2018年秋季 7404-22T数学建模 参考试题

编号&#xff1a;8044 座位号 2018&#xff5e;2019学年度第1学期期末考试 植物病虫害防治基础试题 2019年 1月 一、名词解释 &#xff08;5小题&#xff0c;每题5分&#xff0c;共25分&#xff09; 非传染性病害 抗病性 物理机械防治 植物检疫 年生活史 二、单项选择题…

六种常用的物联网通信协议

本文来自&#xff1a;http://www.ebyte.com/ 随着现在物联网设备的数量不断的增加&#xff0c;这些设备之间的通信连接也成了一个值得我们思考的课题。据预测&#xff0c;到2020年物联网的设备数量将达到204亿台。我们常用的物联网通信协议有很多种&#xff0c;它们具备着不同…

linux 怎么添加path环境变量,Linux下怎么添加和查看PATH环境变量

linux下查看和添加PATH环境变量来自&#xff1a;http://apps.hi.baidu.com/share/detail/32942984$PATH&#xff1a;决定了shell将到哪些目录中寻找命令或程序&#xff0c;PATH的值是一系列目录&#xff0c;当您运行一个程序时&#xff0c;Linux在这些目录下进行搜寻编译链接。…

【渝粤教育】国家开放大学2018年秋季 8669-21T (1)政治经济学 参考试题

试卷代号&#xff1a;0007 座位号 2018——2019学年度第一学期期末考试 文 书 档 案 管 理 试 题 2019年1月 1&#xff0e;公务文书是 的主体。 2&#xff0e;公文的正文部分一般包括 、 、 、附件、 、 、机关印章。 3&#xff0e;按公务文书的性质及其使用范围的不同划分&a…

智能插座常用的两种通信协议——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;这种现成的方…

【渝粤教育】国家开放大学2019年春季 0341-22T高级英语听力(2) 参考试题

试卷代码&#xff1a;0341 2018-2019学年度第二学期期末考试 高级英语听力&#xff08;2&#xff09;试题 2019年7月 注 意 事 项 一、将你的准考证号、学生证号、姓名及分校&#xff08;工作站&#xff09;名称填写在答题纸规定栏内。 考试结束后&#xff0c;把试卷和答题纸放…

linux 软件 名称 更新,linux软件版本管理命令update-alternatives使用详解

linux软件版本管理命令update-alternatives使用详解update-alternatives 命令用于处理linux系统中软件版本的切换&#xff0c;在各个linux发行版中均提供了该命令&#xff0c;命令参数略有区别&#xff0c;但大致是一样的。1、 注册软件以jdk为例&#xff0c;安装了jdk以后&…

物联网技术应用案例

物联网应用的真正价值远远不至于联网小工具和智能冰箱。物联网的不断发展下&#xff0c;物联网应用正在不断的帮公司提高效率&#xff0c;降低成本并推动收入的增长。 但是&#xff0c;虽然您可能会想到很多的比较典型的物联网应用方案&#xff0c;比如常见的工业自动化和农业中…

【渝粤教育】国家开放大学2019年春季 0736-22T烹饪工艺学(2) 参考试题

科目编号&#xff1a;[0736] 座位号 2018-2019学年度第二学期期末考试 烹饪工艺学&#xff08;2&#xff09; 试题 2019年 4 月 一、名词解释&#xff08;本大题共5小题&#xff0c;每小题4分&#xff0c;共计20分&#xff09; 1.热增耗 2&#xff0e;烧 3&#xff0e;上浆工…

【渝粤教育】国家开放大学2019年春季 1062文学英语赏析 参考试题

试卷代号&#xff1a;1062 2 0 1 9年春季学期期末统一考试 文学英语赏析试题 2019年7月 注意事项 一、将你的学号、姓名及分校&#xff08;工作站&#xff09;名称填写在答题纸的规定栏内。考试结束后&#xff0c;把试卷和答题纸放在桌上。试卷和答题纸均不得带出考场。监考人收…