通过粘性仙人掌基元进行延迟加载和缓存

您显然知道什么是延迟加载 ,对吗? 而且您无疑知道缓存 。 据我所知,Java中没有一种优雅的方法来实现它们中的任何一个。 这是我在Cactoos原语的帮助下为自己找到的。

Matteo Garrone的《 Reality(2012)》

假设我们需要一个可以加密某些文本的对象。 以一种更加面向对象的方式讲,它将封装文本并成为其加密形式。 这是我们将如何使用它(让我们先创建测试 ):

interface Encrypted {String asString() throws IOException;
}
Encrypted enc = new EncryptedX("Hello, world!");
System.out.println(enc.asString());

现在,让我们以一个非常原始的方式用一个主要的构造函数来实现它。 加密机制只会在传入数据中的每个字节上加上+1 ,并且会假定加密不会破坏任何内容(一个非常愚蠢的假设,但是对于本示例而言,它将起作用):

class Encrypted1 implements Encrypted {private final String text;Encrypted1(String txt) {this.data = txt;}@Overridepublic String asString() {final byte in = this.text.getBytes();final byte[] out = new byte[in.length];for (int i = 0; i < in.length; ++i) {out[i] = (byte) (in[i] + 1);}return new String(out);}
}

到目前为止看起来正确吗? 我对其进行了测试,并且可以正常工作。 如果输入是"Hello, world!" ,输出将为"Ifmmp-!xpsme\""

接下来,假设我们希望我们的类接受InputStreamString 。 我们想这样称呼它,例如:

Encrypted enc = new Encrypted2(new FileInputStream("/tmp/hello.txt")
);
System.out.println(enc.toString());

这是最明显的实现,具有两个主要的构造函数(同样,实现是原始的,但是可以工作):

class Encrypted2 implements Encrypted {private final String text;Encrypted2(InputStream input) throws IOException {ByteArrayOutputStream baos =new ByteArrayOutputStream();while (true) {int one = input.read();if (one < 0) {break;}baos.write(one);}this.data = new String(baos.toByteArray());}Encrypted2(String txt) {this.text = txt;}// asString() is exactly the same as in Encrypted1
}

从技术上讲,它是可行的,但流读取是在构造函数内部进行的,这是一种不好的做法 。 主要构造函数只能执行属性分配,而次要构造函数只能创建新对象。

让我们尝试重构并引入延迟加载:

class Encrypted3 {private String text;private final InputStream input;Encrypted3(InputStream stream) {this.text = null;this.input = stream;}Encrypted3(String txt) {this.text = txt;this.input = null;}@Overridepublic String asString() throws IOException {if (this.text == null) {ByteArrayOutputStream baos =new ByteArrayOutputStream();while (true) {int one = input.read();if (one < 0) {break;}baos.write(one);}this.text = new String(baos.toByteArray());}final byte in = this.text.getBytes();final byte[] out = new byte[in.length];for (int i = 0; i < in.length; ++i) {out[i] = (byte) (in[i] + 1);}return new String(out);}
}

效果不错,但看起来很丑。 最丑陋的部分当然是这两行:

this.text = null;
this.input = null;

它们使对象可变,并且使用NULL 。 丑陋,相信我。 不幸的是,延迟加载和NULL引用总是在经典示例中并存 。 但是,有一种更好的方法来实现它。 让我们重构类,这次使用Cactoos的 Scalar

class Encrypted4 implements Encrypted {private final IoCheckedScalar<String> text;Encrypted4(InputStream stream) {this(() -> {ByteArrayOutputStream baos =new ByteArrayOutputStream();while (true) {int one = stream.read();if (one < 0) {break;}baos.write(one);}return new String(baos.toByteArray());});}Encrypted4(String txt) {this(() -> txt);}Encrypted4(Scalar<String> source) {this.text = new IoCheckedScalar<>(source);}@Overridepublic String asString() throws IOException {final byte[] in = this.text.value().getBytes();final byte[] out = new byte[in.length];for (int i = 0; i < in.length; ++i) {out[i] = (byte) (in[i] + 1);}return new String(out);}

现在看起来好多了。 首先,只有一个主要构造函数和两个次要构造函数。 其次,对象是不可变的 。 第三,还有很多改进的余地:我们可以添加更多的构造函数来接受其他数据源,例如File或byte数组。

简而言之,应该以“惰性”方式加载的属性在对象内部表示为“功能”(Java 8中的lambda表达式 )。 在我们触摸该属性之前,不会加载该属性。 一旦需要使用它,函数便会执行并得到结果。

这段代码有一个问题。 每当我们调用asString() ,它将读取输入流,这显然是行不通的,因为只有第一次流才会有数据。 在每个后续调用中,流都将为空。 因此,我们需要确保this.text.value()仅执行一次封装的Scalar 。 所有以后的调用都必须返回先前计算的值。 因此,我们需要对其进行缓存 。 方法如下:

class Encrypted5 implements Encrypted {private final IoCheckedScalar<String> text;// same as above in Encrypted4Encrypted5(Scalar<String> source) {this.data = new IoCheckedScalar<>(new StickyScalar<>(source));}// same as above in Encrypted4

StickyScalar将确保仅对其方法value()的第一次调用将传递给封装的Scalar 。 所有其他呼叫将接收第一个呼叫的结果。

要解决的最后一个问题是关于并发性。 我们上面的代码不是线程安全的。 如果创建Encrypted5的实例并将其传递给同时调用asString()两个线程,则结果将是不可预测的,这仅仅是因为StickyScalar不是线程安全的。 不过,还有另一种可以帮助我们的原语,称为SyncScalar

class Encrypted5 implements Encrypted {private final IoCheckedScalar<String> text;// same as above in Encrypted4Encrypted5(Scalar<String> source) {this.data = new IoCheckedScalar<>(new SyncScalar<>(new StickyScalar<>(source)));}// same as above in Encrypted4

现在我们很安全,设计优雅。 它包括延迟加载和缓存。

我现在在许多项目中都使用这种方法,它看起来很方便,清晰且面向对象。

您可能还会发现这些相关的帖子很有趣: 为什么InputStream设计错误 ; 尝试。 最后。 如果。 不。 空值。 ; 每个私有静态方法都是新类的候选人 ; 我将如何重新设计equals() ; 对象行为不可配置 ;

翻译自: https://www.javacodegeeks.com/2017/10/lazy-loading-caching-via-sticky-cactoos-primitives.html

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

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

相关文章

mysql与sim900a_sim900a的应用,基于SIM900A-GPRS模块的远程文件传输实例

SIM900A是一个比较实用的GPRS模块&#xff0c;进行简单的配置就可以进行用于数据传输&#xff0c;配置使用AT指令进行交互&#xff0c;用GPRS远程传输数据时&#xff0c;有两种方式&#xff0c;一种是正常的模式&#xff0c;没法送一次要发送0x1a来开启数据发送&#xff0c;另一…

java语言编程基础_java语言编程基础

java语言基本要素高级语言如c、c#、java等都有一些共同性的东西&#xff1a;关键字、标识符、运算符、注释、数据类型、常量和变量、语句、函数、数组。高级语言在这些要素上大同小异。Java关键字&#xff1a;一些有特定含义&#xff0c;有专门用途的字符串(keyword)。Java中关…

junit mockito_JUnit和Mockito合作

junit mockito这次&#xff0c;我想对测试框架Mockito进行概述。 毫无疑问&#xff0c;这是用于测试Java代码的最受欢迎的工具之一。 我已经对Mockito的竞争对手EasyMock进行了概述。 这篇文章将基于有关EasyMock的示例应用程序。 我的意思是代表咖啡机功能的类。 使用Mockito…

debian10树莓派4安装mysql_树莓派4上如何安装 Raspbian Buster

随着 Raspberry Pi 4 主板的问世&#xff0c;了解如何使用Raspbian Buster设置您的操作系统。你的新Pi 4到了邮箱&#xff0c;你已经设置了办公桌&#xff0c;您已准备好安装操作系统。对于初学者来说&#xff0c;Raspbian为Pi制造商提供了出色的桌面体验。最重要的是&#xff…

借助财务客户评估解决方案在云中构建AppDev

现代JBoss BRMS时代最古老的业务逻辑演示是2012年6月发布的“ 客户评估”示例 。 那时&#xff0c;JBoss BRMS包含规则&#xff0c;事件和流程。 该项目提供了一个完整安装和配置的环境&#xff0c;用于展示该项目和所有可用的BPM组件。 它包括一个带有单元测试的JBoss Develo…

jvm 性能_JVM性能魔术

jvm 性能HotSpot是我们众所周知和喜爱的JVM&#xff0c;是Java和Scala汁流淌的大脑。 多年来&#xff0c;许多工程师对其进行了改进和调整&#xff0c;并且每次迭代时&#xff0c;其代码执行的速度和效率都接近于本机编译代码。 JIT&#xff08;“及时”&#xff09;编译器是…

java高级编程期末考试题_java高级编程考题

Java高级课程测试1在进行swing开发时&#xff0c;经常用的布局管理器有那几种&#xff1f;(5)2Gui组件&#xff0c;容器&#xff0c;框架&#xff0c;到底有怎样的关系&#xff0c;请举例说明&#xff1f;(5)3在进行swing开发中会用到事件处理&#xff0c;那事件处理的三个主要…

spring 事务 会话_测试Spring的“会话”范围

spring 事务 会话在基于Spring的Web应用程序中&#xff0c;bean的作用域可以是用户“会话”。 从本质上讲&#xff0c;这意味着对会话范围Bean的状态更改仅在用户会话范围内可见。 本条目的目的是简单地突出显示Spring Test MVC提供的一种方法&#xff0c;用于测试将会话范围的…

Hollowjars,部署扫描程序以及Wildfly群体为何很棒

在上一篇文章中&#xff0c;我描述了如何使用OpenLiberty和maven作为独立服务器或maven构建的一部分来启动服务器&#xff0c;以及如何创建fatjar包。 在这篇文章中&#xff0c;我正在研究如何使用Wildfly群。 我仍在尝试使MicroProfile在Wildfly full上运行&#xff0c;因此&…

Java调用跟踪系统_Tracer:在分布式系统中的调用跟踪和日志相关

Tracer: Distributed system tracingTracer noun, /ˈtɹeɪsɚ/: A round of ammunition that contains a flammable substance that produces a visible trail when fired in the dark.Tracer is a library that manages custom trace identifiers and carries them through …

java 垃圾回收手动回收_Java垃圾回收(3)

java 垃圾回收手动回收接下来是我的前两篇垃圾收集博客文章&#xff1a; GC热点概述 。 并行垃圾收集器 。 并发标记扫描 Hotspot中的并行垃圾收集器旨在最大程度地减少应用程序进行垃圾收集所花费的时间&#xff0c;这称为吞吐量 。 对于所有应用程序而言&#xff0c;这并不…

java测试netty_《Netty官方文档》基准测试

原文链接 译者&#xff1a;lijunshuNetty有一个模块叫’netty-microbench’&#xff0c;我们可以用他来执行一系列的微型基准测试。Netty-microbench是基于OpenJDK JMH构件的(HotSpot的推荐基准测试方案)。当你开始netty基准测试时&#xff0c;你不需要额外的依赖。运行基准测…

Java命令行界面(第30部分):观察

这个有关Java命令行参数解析的系列文章由四个月来发表的29篇文章组成&#xff0c;涵盖了28个不同的开放源代码库&#xff0c;可用于解析Java命令行参数。 这篇文章收集了可以从本系列的前29篇文章中得出的一些观点&#xff0c;并提供了一些一般性的考虑&#xff0c;以便在选择2…

java导出excel 科学计数法_基于Java将Excel科学计数法解析成数字

需要注意的是一般的科学表达式是1.8E12 1.8E-12而在Excel中的科学表达式是1.8E12 1.8E-12我写的科学计数法的正则表达式是(-?\d\.?\d*)[Ee]{1}[\-]?[0-9]*导入EXCEL数据时将科学计数法解析成数字&#xff0c;Java代码&#xff1a;import java.text.DecimalFormat;import jav…

java描边_shape描边设置是否显示四周描边

android:width"1pt"/>android:topRightRadius"30pt"android:bottomRightRadius"30pt" />效果图如下&#xff1a;这里设置了左边描边不显示设置虚线&#xff1a;android:shape"line">android:dashGap"3pt"android:d…

java 垃圾回收手动回收_Java垃圾回收(2)

java 垃圾回收手动回收并行清理 今天&#xff0c;我们介绍了并行GC的工作原理。 具体来说&#xff0c;这是在Eden上运行并行Scavenge收集器&#xff0c;在Tenured一代上运行Parallel Mark and Sweep收集器的组合。 您可以通过传递-XX&#xff1a; UseParallelOldGC来获得此选项…

java正则表达式性能_译:Java 中的正则表达式性能概述

译者&#xff1a;Darren Luo1. 概述在本快速教程中&#xff0c;我们将展示模式匹配引擎是如何工作的。我们还将介绍在 Java 中优化正则表达式的不同方式。有关正则表达式的的使用介绍&#xff0c;请参阅此文。2. 模式匹配引擎java.util.regex 包使用了一种叫做 Nondeterministi…

带注释的控制器– Spring Web / Webflux和测试

Spring Webflux和Spring Web是两个完全不同的Web堆栈。 但是&#xff0c; Spring Webflux继续支持基于注释的编程模型 使用这两个堆栈定义的端点可能看起来相似&#xff0c;但是测试该端点的方式却大不相同&#xff0c;并且编写此端点的用户必须知道哪个堆栈处于活动状态并相应…

jquery解析java对象数组_Javascript / jQuery初学者:将对象推送到数组

Well you are changing the reference of same object通过示例了解它是如何工作的let a {};let b a;a.name xyz;a.name abc;console.log(a.name)console.log(b.name)所以在上面的示例中我们有两个变量a和b . a是一个对象 .每当我们更新名称时&#xff0c;最后一个值将被新的…

java查看jvm对象个数_jmap-查看 jvm 内存对象信息

jmap 概述命令jmap是一个多功能的命令。它可以生成 java 程序的 dump 文件&#xff0c;也可以查看堆内对象示例的统计信息、查看 ClassLoader 的信息以及 finalizer 队列。参数option&#xff1a;选项参数。pid&#xff1a;需要打印配置信息的进程ID。executable&#xff1a;产…