sci检索没有馆藏号_转变馆藏

sci检索没有馆藏号

您是否曾经想替换过HashSetHashMap使用的equalshashCode方法? 或者有一个List的一些元素类型伪装成的List相关类型的?

转换集合使这成为可能,并且本文将展示如何实现。

总览

转换集合是LibFX 0.3.0的一项功能,该功能将在每天的今天发布。 这篇文章将介绍总体思路,涵盖技术细节并完成一些可能会派上用场的用例。

正在进行的示例是LibFX中包含的功能演示的稍微改编的变体。 请记住,这只是演示该概念的一个示例。

转变馆藏

转换集合是另一个集合的视图(例如,列表到列表,地图到地图等),它似乎包含不同类型的元素(例如,整数而不是字符串)。

通过应用转换从内部元素创建视图元素。 这是按需发生的,因此转换集合本身是无状态的。 作为一个适当的视图,内部集合以及转换视图的所有更改都将反映在另一个视图中(例如Map及其entrySet )。

命名法

转换集合也可以视为装饰器。 我将装饰后的集合称为内部集合,并将其泛型称为内部类型。 转换集合及其通用类型分别称为外部集合和外部类型。

让我们来看一个例子。 假设我们有一组字符串,但是我们知道这些字符串只包含自然数。 我们可以使用一个转换集来获取一个看起来像是整数集的视图。

(类似// "[0, 1] ~ [0, 1]"System.out.println(innerSet + " ~ " + transformingSet);System.out.println(innerSet + " ~ " + transformingSet);的控制台输出。)

Set<String> innerSet = new HashSet<>();
Set<Integer> transformingSet = new TransformingSet<>(innerSet,/* skipping some details */);
// both sets are initially empty: "[] ~ []"// now let's add some elements to the inner set	
innerSet.add("0");
innerSet.add("1");
innerSet.add("2");
// these elements can be found in the view: "[0, 1, 2] ~ [0, 1, 2]"// modifying the view reflects on the inner set
transformingSet.remove(1);
// again, the mutation is visible in both sets: "[0, 2] ~ [0, 2]"

看看转换有多愉快?

由Rooners Toy Photography根据CC-BY-NC-ND 2.0发布。

发布时间由Rooners玩具摄影下的CC-BY-NC-ND 2.0 。

细节

像往常一样,魔鬼在细节中,所以让我们讨论这个抽象的重要部分。

转寄

转换集合是另一个集合的视图。 这意味着它们本身不保存任何元素,而是将所有调用转发给内部/装饰的集合。

他们通过将调用参数从外部类型转换为内部类型并使用这些参数调用内部集合来实现此目的。 然后,将返回值从内部类型转换为外部类型。 对于以集合为参数的调用,这变得有些复杂,但是方法基本上是相同的。

所有转换集合的实现方式都是将方法的每个调用转发到内部集合上的相同方法 (包括default方法 )。 这意味着内部集合对线程安全性,原子性等的任何保证也将由转换集合维护。

转型

转换是通过在构造过程中指定的一对函数来计算的。 一个用于将外部元素转换为内部元素,另一个用于另一个方向。 (对于映射,存在两对这样的对:一对用于键,一对用于值。)

转换函数关于equals必须彼此相反,即, outer.equals(toOuter(toInner(outer))inner.equals(toInner(toOuter(inner))对于所有外部元素和内部元素必须为true。事实并非如此,这些集合的行为可能无法预测。

对于身份而言,情况并非如此,即, outer == toOuter(toInner(outer))可能为false。 详细信息取决于所应用的转换,并且通常未指定-它可能永远不会,有时或永远是正确的。

让我们看看转换函数如何查找我们的字符串和整数集:

private Integer stringToInteger(String string) {return Integer.parseInt(string);
}private String integerToString(Integer integer) {return integer.toString();
}

这就是我们使用它们创建转换集的方式:

Set<Integer> transformingSet = new TransformingSet<>(innerSet,this::stringToInteger, this::integerToString,/* still skipping some details */);

直截了当吧?

是的,但是即使这个简单的示例也包含陷阱。 注意前导零的字符串如何映射到相同的整数。 这可以用于创建不良行为:

innerSet.add("010");
innerSet.add("10");
// now the transforming sets contains the same entry twice:
// "[010, 10] ~ [10, 10]"// sizes of different sets:
System.out.println(innerSet.size()); // "2"
System.out.println(transformingSet.size()); // "2"
System.out.println(new HashSet<>(transformingSet).size()); // "1" !// removing is also problematic
transformingSet.remove(10) // the call returns true
// one of the elements could be removed: "[010] ~ [10]"
transformingSet.remove(10) // the call returns false
// indeed, nothing changed: "[010] ~ [10]"// now things are crazy - this returns false:
transformingSet.contains(transformingSet.iterator().next())
// the transforming set does not contain its own elements ~> WAT?

因此,在使用转换集合时,仔细考虑转换非常重要。 它们必须彼此相反!

但这仅限于实际发生的内部和外部元素就足够了。 在示例中,问题仅在引入带有前导零的字符串时开始。 如果某些业务规则禁止了这些规则,并且这些规则已经正确执行,那么一切都会好起来的。

类型安全

以通常的静态,编译时方式对转换集合进行的所有操作都是类型安全的。 但是,由于collection接口中的许多方法都允许对象(例如Collection.contains(Object) )或未知通用类型的集合(例如Collection.addAll(Collection<?>) )作为参数,因此这并不涵盖所有可能发生在以下情况的情况运行。

请注意,这些调用的参数必须从外部类型转换为内部类型,才能将调用转发到内部集合。 如果使用非外部类型的实例调用它们,则很可能无法将其传递给转换函数。 在这种情况下,该方法可能会抛出ClassCastException 。 尽管这与方法的合同一致,但可能仍然是意外的。

为了降低这种风险,转换集合的构造函数需要使用内部和外部类型的令牌。 它们用于检查元素是否为必需类型,如果不是,则可以毫无例外地优雅地回答查询。

我们终于可以确切地看到如何创建转换集:

Set<Integer> transformingSet = new TransformingSet<>(innerSet,String.class, this::stringToInteger,Integer.class, this::integerToString);

构造函数实际上接受Class<? super I> Class<? super I>所以这也将编译:

Set<Integer> transformingSetWithoutTokens = new TransformingSet<>(innerSet,Object.class, this::stringToInteger,Object.class, this::integerToString);

但是由于一切都是对象,因此对令牌的类型检查变得无用,并且调用转换函数可能会导致异常:

Object o = new Object();
innerSet.contains(o); // false
transformingSet.contains(o); // false
transformingSetWithoutTokens.contains(o); // exception

用例

我要说的是,转换集合是一种非常专业的工具,不太可能经常使用,但在每个分类良好的工具箱中仍然占有一席之地。

重要的是要注意,如果性能至关重要,则可能会出现问题。 每次调用包含或返回元素的转换集合,都会导致至少创建一个(通常是多个)对象。 这些对垃圾收集器施加了压力,并导致通往有效负载的方式的间接级别更高。 (与以往一样,在讨论性能时:首先介绍个人资料!)

那么转换集合的用例是什么? 上面我们已经看到了如何将集合的元素类型更改为另一种。 虽然这代表了总体思路,但我认为这不是一个非常普遍的用例(尽管在某些边缘情况下是有效的方法)。

在这里,我将展示两个更狭窄的解决方案,您可能希望在某些时候使用它们。 但是我也希望这能使您了解如何使用转换集合来解决棘手的情况。 也许您的问题的解决方案在于巧妙地应用此概念。

用Equals和HashCode代替

我一直很喜欢.NET的哈希图(他们称其为字典)如何具有将EqualityComparer作为参数的构造函数 。 通常将在键上调用的所有equalshashCode调用均委派给该实例。 因此有可能即时替换有问题的实现。

当您处理无法完全控制的有问题的旧版代码或库代码时,这可以节省生命。 当需要一些特殊的比较机制时,它也很有用。

通过转换集合,这很容易。 为了使它更加容易,LibFX已经包含一个EqualityTransformingSetEqualityTransformingMap 。 它们修饰另一个集合或映射的实现,并且可以在构造过程中提供键/元素的equalshashCode函数。

假设您想将字符串用作set元素,但为了进行比较,您仅对它们的长度感兴趣。

Set<String> lengthSet = EqualityTransformingSet.withElementType(String.class).withInnerSet(new HashSet<Object>()).withEquals((a, b) -> a.length != b.length).withHash(String::length).build();lengthSet.add("a");
lengthSet.add("b");
System.out.println(lengthSet); // "[a]"

从集合中删除可选性

也许您正在与一个想到在各处使用Optional的想法的人一起工作,然后疯狂地使用它,现在您有了Set<Optional<String>> 。 如果无法修改代码(或您的同事),则可以使用转换集合来获取一个对您隐藏Optional的视图。

同样,实现起来很简单,因此LibFX已经以OptionalTransforming[Collection|List|Set]的形式包含了它。

Set<Optional<String>> innerSet = new HashSet<>();
Set<String> transformingSet =new OptionalTransformingSet<String>(innerSet, String.class);innerSet.add(Optional.empty());
innerSet.add(Optional.of("A"));// "[Optional.empty, Optional[A]] ~ [null, A]"

请注意, null表示空的optional的方式。 这是默认行为,但是您也可以将另一个字符串指定为空可选值的值:

Set<String> transformingSet =new OptionalTransformingSet<String>(innerSet, String.class, "DEFAULT");// ... code as above ...
// "[Optional.empty, Optional[A]] ~ [DEFAULT, A]"

这样可以避免Optional以及null作为元素,但是现在您必须确保永远不会有包含DEFAULT的Optional。 (如果确实如此,则隐式转换不是彼此相反的,这在上面已经看到导致问题了。)

有关此示例的更多详细信息,请查看演示 。

反射

我们已经介绍过,转换集合是另一个集合的视图。 使用类型标记(以最大程度地减少ClassCastExceptions )和一对转换函数(它们必须彼此相反),每个调用都将转发到装饰的集合。 转换后的集合可以维护修饰后的集合所做的关于线程安全性,原子性的所有保证。

然后,我们看到了转换集合的两个特定用例:替换等于和哈希数据结构使用的哈希码,以及从Collection<Optional<E>>删除可选性。

谈谈LibFX

就像我说的那样,转换集合是我的开源项目LibFX的一部分。 如果您考虑使用它,我想指出一些事情:

  • 这篇文章介绍了这个想法和一些细节,但是并不能代替文档。 查看Wiki,获取最新描述和指向Javadoc的指针。
  • 我认真对待测试。 多亏了Guava ,约6.500个单元测试涵盖了转换集合。
  • LibFX是根据GPL许可的。 如果那不适合您的许可模式,请随时与我联系。

翻译自: https://www.javacodegeeks.com/2015/05/transforming-collections.html

sci检索没有馆藏号

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

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

相关文章

c语言中exit和return的区别

点击上方蓝字关注我&#xff0c;了解更多咨询1、返回函数值的return是关键字&#xff0c;exit是一个函数。return是语言级的&#xff0c;它表示调用堆栈的返回&#xff1b;exit是系统调用级的&#xff0c;它表示一个过程的结束。2、return是函数的退出&#xff0c;exit是进程的…

java怎样返回json_java怎么返回json

详细内容本篇文章将介绍如何编写Java程序来返回Json数据&#xff0c;本次以三个方式进行介绍。推荐课程&#xff1a;Java教程&#xff0c;方式1&#xff1a;当然是手敲所有代码&#xff0c;来进行json数据的返回。需要 HttpHttpServletRequest request HttpServletResponse res…

junit测试类叫什么名字_使用Junit测试名称

junit测试类叫什么名字命名测试 当我们创建Junit测试时&#xff0c;通常没有方法名称的实际使用。 Junit运行器使用反射来发现测试方法&#xff0c;并且从版本4开始&#xff0c;您不再被限制以test开始方法的名称。 测试方法的名称用于文档目的。 人们遵循不同的风格。 您可以…

c语言中realloc函数是什么

点击上方蓝字关注我&#xff0c;了解更多咨询1、判断当前指针是否有足够的连续空间。如果足够&#xff0c;扩大ptr指向的地址并返回。如果不够&#xff0c;如何根据size指定的大小分配空间&#xff0c;将原始数据复制到新分配的内存中&#xff0c;然后释放原始ptr指向的区域。2…

java 暂停循环_java小白关于while死循环时处理办法的一发求助帖

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼package greedsnake;import java.awt.Color;import java.awt.Font;import java.awt.Frame;import java.awt.Graphics;import java.awt.Image;import java.awt.event.KeyAdapter;import java.awt.event.KeyEvent;import java.awt.ev…

java jsp学习指南_JSP教程–最终指南

java jsp学习指南编者注&#xff1a; JavaServer Pages&#xff08;JSP&#xff09;技术使您可以轻松创建同时包含静态和动态组件的Web内容。 JSP技术提供了Java Servlet技术的所有动态功能&#xff0c;但提供了一种更自然的方法来创建静态内容。 JSP技术的主要功能包括用于开…

c语言中main函数是什么

点击上方蓝字关注我&#xff0c;了解更多咨询1、main函数是C程序的入口函数&#xff0c;即程序的执行从main函数开始&#xff0c;其他函数的调动也直接或间接地在main函数中调用。2、main函数的返回值用于解释程序的退出状态。若返回0&#xff0c;则表示程序正常退出。返回其他…

什么是通用字符名称?_通用名称

什么是通用字符名称&#xff1f;泛型类型参数名称通常包含一个大写字母字符。 如果您开始阅读有关泛型的官方ORACLE文档&#xff0c;则第一个示例是 /*** Generic version of the Box class.* param <T> the type of the value being boxed*/ public class Box<T>…

c语言中__cplusplus是什么

点击上方蓝字关注我&#xff0c;了解更多咨询1、__cplusplus和extern“C”一般都是配对使用&#xff0c;如果定义了__cplusplus(cpp文件默认定义了该宏)&#xff0c;则采用C语言方式进行编译。2、是在C中特有的&#xff0c;__cplusplus 其实就是C。实例#ifndef __CODERSRC_H__ …

git rollback代码都没了_git回滚线上代码

由于之前自己推代码的时候操作失误&#xff0c;才push代码的时候没有push到dev分支&#xff0c;而是push到了本地master同名分支的线上master分支&#xff0c;覆盖掉了线上在用的代码。在搜索解决办法的时候&#xff0c;发现网上给的信息大多不够全&#xff0c;且很多无用。所以…

c语言中fwirte函数的使用方法示例

点击上方蓝字关注我&#xff0c;了解更多咨询1、fwrite函数用于将缓冲区数据写入文件&#xff0c;并返回成功写入文件的元素数。如果出现错误或到达文件末尾&#xff0c;可能小于nmemb。2、fwrite函数不区分文件的尾部和错误&#xff0c;因此调用者必须使用feof和ferror来判断发…

联通光纤限制连接数_从数百万个光纤(而不是数千个线程)中查询数据库

联通光纤限制连接数jOOQ是在Java中执行SQL的好方法&#xff0c;而Quasar光纤带来了大大提高的并发性 我们很高兴在平行世界的 Fabio Tudone的jOOQ博客上宣布另一个非常有趣的来宾帖子。 Parallel Universe开发了一个开放源代码堆栈&#xff0c;使开发人员可以轻松地在JVM上对…

java 工程新建ivy文件_Hadoop学习之路(八)在eclispe上搭建Hadoop开发环境

一、添加插件将hadoop-eclipse-plugin-2.7.5.jar放入eclipse的plugins文件夹中二、在Windows上安装Hadoop2.7.5版本最好与Linux集群中的hadoop版本保持一致1、将hadoop-2.7.5-centos-6.7.tar.gz解压到Windows上的C盘software目录中2、配置hadoop的环境变量HADOOP_HOMEC:\softwa…

c语言中fclose函数的使用你会吗

点击上方蓝字关注我&#xff0c;了解更多咨询1、C语言fclose函数用于关闭使用fopen成功打开的文件。2、fopen函数和fclose函数总是成对出现。如果文件成功打开fopen函数&#xff0c;请使用fclose函数关闭文件。实例#include <stdio.h> #include <stdlib.h>int main…

悲观锁 引起死锁_悲观锁定时如何避免可怕的死锁-以及Java 8的一些用法!

悲观锁 引起死锁有时您根本无法避免&#xff1a;通过SQL进行悲观锁定。 实际上&#xff0c;当您要在共享的全局锁上同步多个应用程序时&#xff0c;它是一个很棒的工具。 有人可能认为这是在滥用数据库。 如果可以解决您遇到的问题&#xff0c;我们认为可以使用您拥有的工具。…

Java反序列化json内存溢出_fastJson与一起堆内存溢出'血案'

现象QA同学反映登录不上服务器排查问题1–日志级别查看log,发现玩家登录的时候抛出了一个java.lang.OutOfMemoryError大概代码是向Redis序列化一个PlayerMirror镜像数据,但是在JSON.toJSONString的时候出现了错误.比较清晰&#xff0c;即序列化的时候expandCapacity,内存不足。…

c语言中预处理器是什么

点击上方蓝字关注我&#xff0c;了解更多咨询1、C语言有预处理器&#xff0c;Java中没有这个概念&#xff0c;其实只是文本替换工具。2、C的预处理器&#xff0c;即CPP&#xff0c;将在实际编译器中完成处理&#xff0c;所有预处理命令将从#开始。实例#include <stdio.h>…

愚弄dnn_不要被泛型和向后兼容性所愚弄。 使用泛型类型

愚弄dnn最近&#xff0c;我与jOOQ的早期客户Ergon的 Sebastian Gruber进行了非常有趣的讨论&#xff0c;我们与之保持了密切联系。 与Sebastian交谈使我们的工程团队得出了一个结论&#xff0c;即我们应该完全重写jOOQ API。 现在&#xff0c;我们已经有很多用于各种用途的泛型…

php asp.net 代码量少,.NET_asp.net 反射减少代码书写量, 复制代码 代码如下:public b - phpStudy...

asp.net 反射减少代码书写量public bool Add(Liuyan refmodel){string sql "insert into liuyan(name,phone,zhiwei,gongsi,addr,country,dianyou,content,adddate)values(name,phone,zhiwei,gongsi,addr,country,dianyou,content,adddate)";OleDbParameter[] param…

c语言strcat_s函数如何使用

点击上方蓝字关注我&#xff0c;了解更多咨询1、strcat_s函数将strSource指向的字符串添加到其它字符串结尾。因此需要确保strDestination有足够的内存空间来容纳strSource和strDestination两个字符串&#xff0c;否则会导致溢出错误。2、strDestination末端的\0将被覆盖。strS…