纹理和基元_通过粘性仙人掌基元进行延迟加载和缓存
纹理和基元
您显然知道什么是延迟加载 ,对吗? 而且您无疑知道缓存 。 据我所知,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\""
。
接下来,假设我们希望我们的类接受InputStream
和String
。 我们想这样称呼它,例如:
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
纹理和基元
纹理和基元_通过粘性仙人掌基元进行延迟加载和缓存相关推荐
- 通过粘性仙人掌基元进行延迟加载和缓存
您显然知道什么是延迟加载 ,对吗? 而且您无疑知道缓存 . 据我所知,Java中没有一种优雅的方法来实现它们中的任何一个. 这是我在Cactoos原语的帮助下为自己找到的. Matteo Garron ...
- 几何基元_.NET异步协调基元中的两种技术比较
几何基元 Last week in my post on updating my Windows Phone 7 application to Windows 8 I shared some code ...
- 运动基元_发现大量Java基元集合处理
运动基元 在阅读博客文章5减少Java垃圾收集开销的技巧时 ,我想起了一个名为Trove的小型Java收集库,该库"为Java提供了高速的常规和原始收集". 我对将Trove应用到 ...
- BZOJ_1778_[Usaco2010 Hol]Dotp 驱逐猪猡_概率DP+高斯消元
BZOJ_1778_[Usaco2010 Hol]Dotp 驱逐猪猡_概率DP+高斯消元 题意: 奶牛们建立了一个随机化的臭气炸弹来驱逐猪猡.猪猡的文明包含1到N (2 <= N <= 3 ...
- 小肩膀POST+JS第三期(价值1000元)_高清带源码
小肩膀POST+JS第三期(价值1000元)_高清带源码 .课程整体介绍 2.谷歌开发者工具 3.火狐firebug组件 4.火狐开发者工具 5.HTTP Analyzer V7 6.Fiddler ...
- 2 shell 锂基脂_壬二酸和癸二酸制备的复合锂基脂到底有那些差别!
2019年12月21-22日 深圳<润滑脂生产技术培训班>烃基脂,钙基脂,锂基脂,复合锂基脂.铝基脂,复合铝,磺酸钙脂等润滑脂的生产配方设计及生产工艺和流程,专家现场答疑,报名咨询:189 ...
- 六元均匀直线阵的各元间距为_实验二 均匀直线阵
实验二 均匀直线阵 一.实验目的: 通过 MATLAB 编程,了解均匀直线阵的辐射特性,熟悉影响天线阵辐射的各种因素及其 产生的影响. 二.实验环境: MATLAB 软件 三.实验原理: 单个天线的方 ...
- 井通swtc能不能涨到2元_买一支2块到3块之间的股票,买几十万股吗?这样操作效果怎么样?...
有很多新股民有一种看法,认为高价股风险很大,那么可不可以买2到3元的低价股,是不是风险就很小,以后上涨的力度就会很大? 这是很多股民都存在的一个误区,也是很多股市的所谓高手的误导,他们说:只要买入低价 ...
- python123百钱买百鸡_求解百钱买百鸡问题。假设大鸡 5 元一只,中鸡 3 元一只,小鸡 1 元三只,现有 100 元钱想买 100 只鸡,有多少种买法?截图代码和运行结果_学小易找答案...
[填空题]表达式 'apple.peach,banana,pear'.find('ppp') 的值为 ________ . [填空题]已知 x = '123' 和 y = '456' ,那么表达式 x ...
最新文章
- 学习在Unity中创建一个动作RPG游戏
- 微信公众号开发用书php,php微信公众号开发(3)php实现简单微信文本通讯
- 语言 上课点名 缺勤_主播日记5 | “云端”传递的C语言程序设计实验课
- 【MPI程序】向量乘法,向量点积(高性能计算)
- 服务器系统自带虚拟机吗,现在所说的服务器虚拟化,也就是在vmware虚拟机上搭建的吗...
- python 抓取微博评论破亿_如果利用Python分析14亿条数据!资深程序员手把手教你!过亿级!...
- Android studio 使用心得(八)----测试程序单元测试
- 华为鸿蒙11什么时候发布,原创 华为EMUI11正式发布,今年12月可升级为鸿蒙OS2.0国产操作系统...
- java 定时任务 quartz 时间表达式Cron总结
- Python之面向对象-类与 类之间的关系
- springboot毕设项目网上商城系统8l44b(java+VUE+Mybatis+Maven+Mysql)
- 【毕业设计】 基于单片机的移动共享充电宝设计与实现 - 物联网嵌入式 stm32 c51
- 目标窗口检测算法-NMS非极大值抑制
- 解密Uber自动驾驶系统,警方披露撞人案细节
- schedule定时任务
- apt查看安装包可用版本号
- IDEA绿色护眼色设置(含代码区 项目结构区 运行区)
- HBase二级索引的设计与应用(详解)
- 硬件nat关闭还是开启_NAT(Network Address Translation)网络地址转换技术详解
- 服务器显示free怎么回事,free云服务器