java枚举有啥不好
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java枚举有啥不好相关的知识,希望对你有一定的参考价值。
我在java webapp项目里面使用枚举,但是主管总是对我使用枚举有意见,我问原因他说没有看到那个书上用枚举,他说如果看到那本书上有写使用枚举的以后就不说我了,那我就觉得奇怪了,java枚举有哪些缺点,为什么没有普及。网络上没有太多说java有哪些优缺点的
没有他说的那么绝对。没有不好用的,只有不适合用、不擅长用的。在webapp里面,用枚举不如用xml或properties或数据字典,因为维护容易,用枚举得改类,再编译,再替换到服务器上,而用后面的直接修改服务器文件或者在系统上配置就OK了 参考技术A 看看枚举的写法吧你们。
需要get set方法支持的类型
就会有实例化风险
一实例化相对就消耗内存
谁爱用用 反正我不用
一群菜鸟 只会跟风不会思考
35岁淘汰的就是你们 参考技术B 枚举相对于静态常量需要更多的内存 参考技术C 枚举的内存开销比较大吧 参考技术D 确实莫名其妙 。我也想知道。估计是那人书看的比较少吧。呵呵
Lazy I/O 有啥不好?
【中文标题】Lazy I/O 有啥不好?【英文标题】:What's so bad about Lazy I/O?Lazy I/O 有什么不好? 【发布时间】:2011-08-19 01:22:18 【问题描述】:我通常听说生产代码应避免使用延迟 I/O。我的问题是,为什么?除了玩弄之外,还可以使用 Lazy I/O 吗?是什么让替代品(例如枚举器)更好?
【问题讨论】:
【参考方案1】:Lazy IO 的问题是,释放您获得的任何资源在某种程度上是不可预测的,因为它取决于您的程序如何使用数据——它的“需求模式”。一旦您的程序删除了对该资源的最后一个引用,GC 最终将运行并释放该资源。
惰性流是一种非常方便编程的风格。这就是为什么 shell 管道如此有趣和流行的原因。
但是,如果资源受到限制(如在高性能场景中,或希望扩展到机器极限的生产环境中),则依靠 GC 进行清理可能是一个不充分的保证。
有时您必须急切地释放资源,以提高可扩展性。
那么有哪些惰性 IO 替代方案并不意味着放弃增量处理(这反过来又会消耗太多资源)?嗯,我们有基于 foldl
的处理,也称为迭代器或枚举器,由 Oleg Kiselyov in the late 2000s 引入,并被许多基于网络的项目推广。
我们不是将数据作为惰性流或一个大批量处理,而是通过基于块的严格处理进行抽象,并保证在读取最后一个块后资源的最终确定。这就是基于迭代的编程的精髓,它提供了非常好的资源约束。
基于迭代的 IO 的缺点是它有一个有点笨拙的编程模型(大致类似于基于事件的编程,而不是基于线程的控制)。在任何编程语言中,这绝对是一种先进的技术。而对于绝大多数编程问题,惰性IO完全可以满足。但是,如果您要打开许多文件,或者在许多套接字上进行通信,或者以其他方式同时使用许多资源,那么迭代器(或枚举器)方法可能是有意义的。
【讨论】:
因为我刚刚从关于惰性 I/O 的讨论中关注到这个老问题的链接,所以我想我应该添加一个注释,从那时起,迭代器的大部分尴尬已经被新的pipes 和 conduit 等流媒体库。【参考方案2】:Dons 提供了一个很好的答案,但他忽略了(对我而言)迭代器最引人注目的特性之一:它们使空间管理的推理变得更容易,因为必须明确保留旧数据。考虑:
average :: [Float] -> Float
average xs = sum xs / length xs
这是众所周知的空间泄漏,因为必须将整个列表 xs
保留在内存中才能计算 sum
和 length
。通过创建折叠可以成为高效的消费者:
average2 :: [Float] -> Float
average2 xs = uncurry (/) <$> foldl (\(sumT, n) x -> (sumT+x, n+1)) (0,0) xs
-- N.B. this will build up thunks as written, use a strict pair and foldl'
但是对于每个流处理器都必须这样做有点不方便。有一些概括 (Conal Elliott - Beautiful Fold Zipping),但它们似乎没有流行起来。但是,迭代器可以为您提供类似级别的表达。
aveIter = uncurry (/) <$> I.zip I.sum I.length
这不如折叠有效,因为列表仍然会迭代多次,但是它是按块收集的,因此可以有效地对旧数据进行垃圾收集。为了破坏该属性,有必要显式保留整个输入,例如使用 stream2list:
badAveIter = (\xs -> sum xs / length xs) <$> I.stream2list
迭代器作为编程模型的状态是一项正在进行的工作,但它比一年前要好得多。我们正在了解哪些组合器有用(例如zip
、breakE
、enumWith
),哪些不太有用,结果内置的迭代器和组合器不断提供更多的表现力。
也就是说,Dons 是正确的,他们是一种先进的技术;我当然不会对每个 I/O 问题都使用它们。
【讨论】:
【参考方案3】:我一直在生产代码中使用惰性 I/O。就像唐提到的那样,这只是在某些情况下才会出现的问题。但是只读取几个文件就可以了。
【讨论】:
我也使用惰性 I/O。当我想要更多地控制资源管理时,我会求助于迭代器。【参考方案4】:更新: 最近在 haskell-cafe Oleg Kiseljov showed 上,unsafeInterleaveST
(用于在 ST monad 中实现惰性 IO)非常不安全 - 它破坏了等式推理。他表明它允许构造bad_ctx :: ((Bool,Bool) -> Bool) -> Bool
这样
> bad_ctx (\(x,y) -> x == y)
True
> bad_ctx (\(x,y) -> y == x)
False
即使==
是可交换的。
惰性 IO 的另一个问题:实际的 IO 操作可以推迟到为时已晚,例如在文件关闭之后。引用Haskell Wiki - Problems with lazy IO:
例如,一个常见的初学者错误是在一个文件读完之前关闭它:
wrong = do fileData <- withFile "test.txt" ReadMode hGetContents putStr fileData
问题是 withFile 在强制 fileData 之前关闭句柄。正确的做法是把所有的代码都传给withFile:
right = withFile "test.txt" ReadMode $ \handle -> do fileData <- hGetContents handle putStr fileData
这里,数据在 withFile 完成之前被消费。
这通常是意料之外且容易犯的错误。
另请参阅:Three examples of problems with Lazy I/O。
【讨论】:
实际上将hGetContents
和withFile
结合起来是没有意义的,因为前者将句柄置于“伪关闭”状态并会(懒惰地)为您处理关闭,因此代码完全等同于@ 987654332@,甚至没有hClose
的openFile
。这基本上就是惰性 I/O 。如果你不使用readFile
、getContents
或hGetContents
,你就没有使用惰性 I/O。例如line <- withFile "test.txt" ReadMode hGetLine
工作正常。
@Dag:虽然hGetContents
会为您处理关闭文件,但也可以自己“提前”关闭它,这有助于确保资源以可预测的方式释放。【参考方案5】:
到目前为止还没有提到惰性 IO 的另一个问题是它具有令人惊讶的行为。在一个普通的 Haskell 程序中,有时很难预测程序的每个部分何时被评估,但幸运的是,由于纯度,除非你有性能问题,否则它真的无关紧要。当引入惰性 IO 时,代码的评估顺序实际上会影响其含义,因此您习惯认为无害的更改可能会给您带来真正的问题。
例如,这里有一个关于代码的问题,看起来很合理,但由于延迟 IO 而变得更加混乱:withFile vs. openFile
这些问题并不总是致命的,但这是另外一回事,而且我个人会避免懒惰的 IO,除非预先完成所有工作存在真正的问题。
【讨论】:
以上是关于java枚举有啥不好的主要内容,如果未能解决你的问题,请参考以下文章