Java 8:使用交替接口公开的类型安全地图生成器

动态展示您的课程

当我是Java新手时,我记得当时想过应该有一种方法可以删除或隐藏我不想公开的类中的方法。 就像用private方法或类似方法覆盖public方法一样(哪种情况是不可能的,也不应该是不可能的)。 显然,今天,我们都知道,通过暴露
interface

公爵和尖顶露出另一种样子...

公爵和尖顶露出另一种样子……

通过使用名为Alternating Interface Exposure的方案,我们可以动态查看类的方法并输入安全类型,以便同一类可以强制实施应该使用的模式。

让我举个例子。 假设我们有一个Map构建器,可以在构建实际Map之前先相继添加键和值来调用它。 Alternating Interface Exposure方案使我们能够确保调用key()方法和value()的次数完全相同,并且只有在存在该调用时, build()方法才可调用(例如在IDE中可见)。键和值一样多。

我正在参与的开源项目Speedment中使用了Alternating Interface Exposure方案。 在Speedment中,例如,在构建类型安全的Tuple时使用该方案,随后在向TupleBuilder添加元素之后将构建该类型安全的Tuple 。 这样,如果我们编写TupleBuilder.builder().add("Meaning of Life).add(42).build() ,我们可以得到类型化的Tuple2<String, Integer> = {“生命的含义”,42} TupleBuilder.builder().add("Meaning of Life).add(42).build()

使用动态地图生成器

我在以前的一些文章中(例如这里 )多次写过关于Builder模式的文章,如果您不熟悉这个概念,我鼓励您在阅读之前重新阅读有关此问题的文章。

当前的任务是产生一个Map构建器,它使用许多上下文相关的接口动态地公开许多实现方法。 此外,构建器应在首次使用它们时“学习”其键/值类型,然后对其余条目实施相同类型的键/值。

这是一个示例,说明一旦开发人员如何在代码中使用该构建器:

public static void main(String[] args) {// Use the type safe builderMap<Integer, String> map = Maps.builder().key(1)                 // The key type is decided here for all following keys.value("One")           // The value type is decided here for all following values.key(2)                 // Must be the same or extend the first key type.value("Two")           // Must be the same type or extend the first value type.key(10).value("Zehn'") // And so on....build();               // Creates the map!// Create an empty mapMap<String, Integer> map2 = Maps.builder().build();}}

在上面的代码中,一旦我们开始通过调用key(1)使用Integer,构建器将仅接受作为Integer实例的其他键。 值也是如此。 一旦我们调用value("one") ,就只能使用作为String实例的对象。 例如,如果尝试写入value(42)而不是value("two") ,我们将立即在IDE中看到错误。 另外,当我们使用代码完成功能时,大多数IDE:都将能够自动选择合适的候选对象。

让我详细说明一下:

初次使用

该构建器是使用Maps.builder()方法创建的,返回的初始视图允许我们调用:

  1. build()生成一个空的Map (如上面的第二个“空地图”示例)
  2. key(K key) ,该密钥将密钥添加到构建器并确定所有后续密钥的类型(= K)(例如上述key(1)

一旦调用了初始key(K key) ,该构建器的另一个视图将显示为仅公开:

  1. value(V value) ,它向构建器添加一个值,并为所有后续值(如value("one") )决定类型(= V)

注意,由于键和值的数量不同, build()方法不会在此状态下公开。 编写Map.builder().key(1) .build() ; 完全是非法的,因为没有与key 1关联的值。

后续用法

现在已经确定了键和值类型,构建器将根据要调用的key()value()在显示的两个交替接口之间进行切换。 如果调用key() ,则公开value() ;如果调用value() ,则公开key()build()

建造者

一旦确定类型,这是构建器使用的两个交替接口:

public interface KeyBuilder<K, V> {ValueBuilder<K, V> key(K k);Map<K, V> build();}
public interface ValueBuilder<K, V> {KeyBuilder<K, V> value(V v);}

请注意,一个接口如何返回另一个接口,从而导致暴露的交替接口无限流动。 这是使用交替接口的实际构建器:

public class Maps<K, V> implements KeyBuilder<K, V>, ValueBuilder<K, V> {private final List<Entry<K, V>> entries;private K lastKey;public Maps() {this.entries = new ArrayList<>();}@Overridepublic ValueBuilder<K, V> key(K k) {lastKey = k;return (ValueBuilder<K, V>) this;}@Overridepublic KeyBuilder<K, V> value(V v) {entries.add(new AbstractMap.SimpleEntry<>(lastKey, v));return (KeyBuilder<K, V>) this;}@Overridepublic Map<K, V> build() {return entries.stream().collect(toMap(Entry::getKey, Entry::getValue));}public static InitialKeyBuilder builder() {return new InitialKeyBuilder();}}

我们看到实现类实现了两个交替接口,但是仅根据调用key()value()才返回其中一个接口。 我通过创建两个初始帮助类来“欺骗”一点,这两个初始帮助类负责尚未确定键和值类型的初始阶段。 为了完整起见,下面还显示了两个“欺诈”类:

public class InitialKeyBuilder {public <K> InitialValueBuilder<K> key(K k) {return new InitialValueBuilder<>(k);}public <K, V> Map<K, V> build() {return new HashMap<>();}}
public class InitialValueBuilder<K> {private final K k;public InitialValueBuilder(K k) {this.k = k;}public <V> KeyBuilder<K, V> value(V v) {return new Maps<K, V>().key(k).value(v);}}

后面的类以与主构建器类似的方式工作,即InitialKeyBuilder返回InitialValueBuilder ,而InitialValueBuilder创建一个类型化的构建器,该生成器可以通过交替返回KeyBuilderValueBuilder来无限期使用。

结论

当您需要类的类型安全和上下文感知模型时,“ 交替接口暴露”方案很有用。 您可以使用此方案为您的类制定和实施许多规则。 这些类的使用将更加直观,因为上下文相关的模型及其类型一直传播到IDE。 该模式还提供了更强大的代码,因为在设计阶段就很早就发现了潜在的错误。 我们将在编码时看到潜在的错误,而不是失败的测试或应用程序错误。

翻译自: https://www.javacodegeeks.com/2016/03/java-8-type-safe-map-builder-using-alternating-interface-exposure.html

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

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

相关文章

nodejs面试题

1、为什么用Nodejs,它有哪些缺点&#xff1f; 事件驱动&#xff0c;通过闭包很容易实现客户端的生命活期。不用担心多线程&#xff0c;锁&#xff0c;并行计算的问题V8引擎速度非常快对于游戏来说&#xff0c;写一遍游戏逻辑代码&#xff0c;前端后端通用当然Nodejs也有一些缺点…

sts-bundle的使用_使用WS-Trust / STS采样器扩展JMeter

sts-bundle的使用JMeter没有对WS-Security或WS-Trust的任何内置支持&#xff0c;这使我为JMeter开发了此STS采样器–可以在负载测试STS时使任何人的生活变得更好。 首先&#xff0c;您需要拥有Apache JMeter发行版。 我正在使用v2.7。 然后&#xff0c;您可以从此处下载sts.sam…

001_jdk配置

配置JAVA_HOME,CLASSPATH,PATH 其中JAVA_HOME必须的 JAVA_HOMEE:\java\jdk1.8.0_77 CLASSPATH(告诉java程序运行时&#xff0c;你的类或者类库在哪里) .; E:\java\jdk1.8.0_77\lib\dt.jar;E:\java\jdk1.8.0_77\lib\tools.jar;E:\java\jdk1.8.0_77\jre\lib\rt.jar 改成变量 .;%J…

Spring MVC 4快速入门Maven原型得到了改进–更多Java 8功能

对于所有有兴趣在没有Spring Boot的情况下快速引导Spring 4应用程序的开发人员&#xff0c;请检查刚刚更新的我的Spring MVC 4 Quickstart Maven原型。 原型已经将Java 8用作目标平台已有一段时间了&#xff0c;但是不支持特定的Java 8功能。 最近的更改带来了Thymeleaf&#x…

python -- join()

python -- join()pythonjoinos月似当时&#xff0c;人似当时否&#xff1f;总 在 python 中&#xff0c;一共有两个 join 方法&#xff0c;一个是 str.join(),另一个是 os.path.join() &#xff0c;这里只了解前一种 str.join(iterable) 官方文档 Return a string which is the…

easymock教程_EasyMock教程–入门

easymock教程在本文中&#xff0c;我将向您展示EasyMock是什么&#xff0c;以及如何使用它来测试Java应用程序。 为此&#xff0c;我将创建一个简单的Portfolio应用程序&#xff0c;并使用JUnit&#xff06;EasyMock库对其进行测试。 在开始之前&#xff0c;让我们首先了解使用…

python 函数、面向对象

一、函数 1、定义个函数&#xff0c;可以对输入的数据进行排序&#xff0c; 通过参数来决定是正向排序还是反向排序。 number input(请输入一串数字&#xff1a;) number_list list(number) def sort_number(*args, s0): if s 0: number_map map(int,args)result sorted…

Spark数据倾斜解决方案(转)

本文转发自技术世界&#xff0c;原文链接 http://www.jasongj.com/spark/skew/ Spark性能优化之道——解决Spark数据倾斜&#xff08;Data Skew&#xff09;的N种姿势 发表于 2017-02-28 | 更新于 2017-10-17 | 本文结合实例详细阐明了Spark数据倾斜的几种场景以及对应的解…

JavaParser入门:以编程方式分析Java代码

我最喜欢的事情之一是解析代码并对其执行自动操作。 因此&#xff0c;我开始为JavaParser做出贡献&#xff0c;并创建了两个相关项目&#xff1a; java-symbol-solver和Effectivejava 。 作为JavaParser的贡献者&#xff0c;我反复阅读了一些非常类似的问题&#xff0c;这些问…

python Django基本介绍

创建Django项目并运行 实验环境&#xff1a; Ubuntu 16.04下安装好Anaconda3 Windows下安装好PyCharm 实验步骤 一、创建django工程 在Ubuntu 16.04下执行下面的命令。 &#xff08;1&#xff09;创建一个python3的虚拟环境&#xff08;如果已经创建&#xff0c;忽略此步&…

Android 热补丁动态修复框架小结

Android 热补丁动态修复框架小结转载于:https://www.cnblogs.com/zhujiabin/p/7923233.html

C语言中关于结构体的理解

在c语言中我们如果需要去表示一个学生的特征&#xff0c;例如名字年龄成绩&#xff0c;这些信息我们就需要用到结构体来描述了。 struct stu{char name[20]; //姓名int age; //年龄float score; //成绩 }; struct(结构体)&#xff1a;是由一系列具有相同类型…

GoldenGate Logdump基本使用

Logdump是GoldenGate复制软件中附带的一个工具软件&#xff0c;在OGG的目录下可以找到。这个工具主要用于分析OGG生成的队列文件&#xff0c;查找记录、统计队列文件中的数据等。 在OGG安装目录下执行logdump.exe or ./logdump即可进入命令行。 开始查找记录之前&#xff0c;先…

js 里面的键盘事件对应的键码

js 里面的键盘事件经常用到&#xff0c;所以收集了键盘事件对应的键码来分享下&#xff1a; keyCode 8 BackSpace BackSpace keyCode 9 Tab Tab keyCode 12 Clear keyCode 13 Enter keyCode 16 Shift_L keyCode 17 Control_L keyCode 18 Alt_L keyCode 19 Pause keyCo…

.bam.bai的意义_业务活动监视器(BAM)2.0带来的革命

.bam.bai的意义生产兼具精益和企业价值的中间件是一项艰巨的工作。 它要么不存在&#xff0c;要么需要创新的思维&#xff08;很多&#xff09;&#xff0c;并且需要在实现中反复进行。 业务风险很大&#xff0c;但是如果您做对了&#xff0c;它就会使您领先于其他任何公司。 这…

数据结构和算法之排序五:选择排序

我们上一篇谈到了冒泡排序&#xff0c;其实我也说了&#xff0c;这两个排序方式何其相似&#xff0c;如果掌握了冒泡排序再来进行选择排序的理解我觉得完全没有太大的问题。那么什么叫做选择排序呢&#xff1f;我们可以理解为矮子里面挑高个&#xff0c;比如说呀有一个富翁来到…

Visual Studio Code使用问题

1、打开vscode黑屏 右击vscode快捷方式–>属性–>兼容性—>兼容模式打钩 重启vscode就可以了。 2、vscode终端没有显示路径&#xff0c;不能输入 显示如下图 则关闭VS Code ,右键单击VS Code 图标&#xff0c;选择属性->兼容性&#xff0c;取消勾选 已兼容模式运…

Java社区调查结果:74%的开发人员希望减少详细程度

一个新的JDK增强建议&#xff08;JEP&#xff09;在Java社区中风起云涌&#xff1a;JEP286。该建议建议在Java的未来版本中引入局部变量类型推断&#xff0c;以简化Java应用程序的编写。 在下面的文章中&#xff0c;我们将解释它的含义以及它将如何影响您的代码。 新帖&#…

【BZOJ2300】[HAOI2011]防线修建 set维护凸包

【BZOJ2300】[HAOI2011]防线修建 Description 近来A国和B国的矛盾激化&#xff0c;为了预防不测&#xff0c;A国准备修建一条长长的防线&#xff0c;当然修建防线的话&#xff0c;肯定要把需要保护的城市修在防线内部了。可是A国上层现在还犹豫不决&#xff0c;到底该把哪些城市…

Sass笔记(CSS 的预编译语言)

在线转换&#xff1a;https://www.sass.hk/css2sass/ Sass 是一种 CSS 的预编译语言。它提供了 变量&#xff08;variables&#xff09;、嵌套&#xff08;nested rules&#xff09;、 混合&#xff08;mixins&#xff09;、 函数&#xff08;functions&#xff09;等功能。 S…