缩略显示
[置顶] 一个程序员的多年珍藏(1月23日最新更新)
文章分类:Java编程
程序员珍藏的东西会是什么?呵呵,除了平时写的代码,就是那些百看不厌的电子书了。
昨天很郁闷,我用了5年的移动硬盘,莫名奇妙的坏掉了。里面40G的资料全部报销了。
为了不再重蹈覆辙,我决定把重要的电子书都放到网络硬盘上去备份。索性将这些资料的下载方式公布出来,与大家分享,一定会有你想要的!
下载的兄弟注意了,点击下载后,可以在url中看到后缀名:),如果把后缀名改错了就看不了了,所有的资料都有人下载过了,应该都能看。
Python相关的资料还可以看:http://jythoner.javaeye.com/blog/569987
新书区
Python源码剖析: 下載文件 Python源码剖析.chm (670.21 KB)
Python黑客: 下載文件 Gray Hat Python Python Programming for Hackers and Reverse Engineers.pdf (3.30 MB)
上一本书的源码: 下載文件 ghpython_src.zip (606.56 KB)
php5手册: 下載文件 php5手册.chm (5.70 MB)
Google Adsense的秘密: 下載文件 《Google Adsense的秘密》中文版.pdf (905.51 KB)
《Google_Cash》快速致富手册,主要讲如何利用Google Adwords网赚: 下載文件 《Google_Cash》快速致富手册.pdf (2.23 MB)
Google cash补充,Day job killer中文版: 下載文件 跟打工生涯说再见.pdf (749.96 KB)
Java
Java API 1.6中文版: 下載文件 JDK API 1.6.0 zh_CN.CHM (35.12 MB)
下載文件 《java编程思想》第三版 第四版包括习题答案(8.92 MB)
下載文件 Java Collections.pdf (1.33 MB)
下載文件 Java_Collections-src.zip (150.21 KB)
下載文件 Java IO.chm (2.76 MB)
下載文件 Java NIO.pdf (1.40 MB)
下載文件 IO.gif (36.00 KB)
下載文件 JDBC Recipes A Problem Solution Approach.pdf (5.23 MB)
下載文件 Java Network Programming.chm (1.97 MB)
下載文件 Servlets and JavaServer Pages The J2EE Tier.pdf (4.73 MB)
英文版: 下載文件 Java.Threads.3rd.Edition.chm (685.45 KB)
中文版: 下載文件 java线程.pdf (20.26 MB)
Java与模式绝对高清版: 下載文件 Java与模式.pdf (39.64 MB)
为什么要看上面的那些书?请看我以前转 的 帖子:Java 推荐读物与源代码阅读: http://jythoner.javaeye.com/blog/311434
Java程序员必备的书籍,比API更有用: 下載文件 The Java Developers Almanac 1.4.chm (679.90 KB)
找工作必备: 下載文件 125条常见的java面试笔试题大汇总.pdf (95.17 KB)
一本Java实现的数据结构书籍: 下載文件 Java数据结构与算法.pdf (25.35 MB)
学Struts,Hibernate,Spring,如果不懂反射的原理,就不用谈了: 下載文件 Java Reflection In Action.pdf (1.70 MB)
JMX,Jboss的基础,jdk5后被纳入进来: 下載文件 JMX In Action.pdf (4.76 MB)
Junit绝对经典书籍: 下載文件 Junit in action.pdf (15.64 MB)
一本专门讲jdk1.5新特性的书,英文版: 下載文件 Java 1.5 Tiger A Developer's Notebook.chm(411.57 KB)
中文版: 下載文件 Java 1.5 Tiger A Developer's Notebook.pdf (7.23 MB)
源代码: 下載文件 Java 1.5 Tiger A Developer's Notebook.zip (38.18 KB)
下載文件 Java极限编程.pdf (23.96 MB)
下載文件 uml distilled.chm (1.52 MB)
下載文件 Expert One-on-One J2EE Design and Development.chm (10.66 MB)
下載文件 测试驱动开发.pdf (6.89 MB)
如果不知道上面4本书的作者,那么基本上你的Java算白学了
Ant手册: 下載文件 Apache Ant Manual 1.7.chm (949.48 KB)
英文版: 下載文件 UML for Java Programmers.pdf (1.77 MB)
中文版: 下載文件 UML for Java Programmers中文版.pdf (2.51 MB)
源代码: 下載文件 UML for Java Programmers.rar (465.36 KB)
下載文件 Java实用系统开发指南.pdf (57.82 MB)
下載文件 JAVA优化编程.pdf (13.58 MB)
下載文件 Java and XML(英文第三版).chm (3.79 MB)
下載文件 Apress.Pro.XML.Development.with.Java.Technology.pdf (12.83 MB)
Eclipse插件开发
一个高手推荐的4本必读书:
中文版: 下載文件 Contributing to Eclipse Principles, Patterns and PlugIns.pdf (23.29 MB)
英文版: 下載文件 Contributing to Eclipse Principles, Patt ... (4.93 MB)
下載文件 Eclipse Building Commercial-Quality Plug-ins.chm (20.11 MB)
下載文件 Eclipse Modeling Framework.chm (3.20 MB)
下載文件 Eclipse Rich Client Platform Designing Coding and Packaging Java Applications.chm(4.90 MB)
下載文件 SWT-A Developer's Note Book.chm (1.53 MB)
API: 下載文件 swt jface API.pdf (7.59 MB)
Linux
中国Linuxer应该没人不知道鸟哥,这本书是基础版与网络版的合集: 下載文件 鸟哥的Linux私房菜.pdf (36.43 MB)
命令大全,支持查找: 下載文件 Linux命令大全(修改版).chm (345.84 KB)
无意间发现的,里面记载了很多实用的命令: 下載文件 Unix Toolbox.pdf (350.31 KB)
学习shell编程必读,里面包括一份详细的学习笔记: 下載文件 LINUX与UNIX SHELL编程指南.zip (19.22 MB)
Sed和Awk唯一的书: 下載文件 Sed and Awk.pdf 中文版(6.89 MB)
下載文件 AWK单行脚本快速参考.doc (52.50 KB)
下載文件 SED单行脚本快速参考.doc (91.00 KB)
一张RE图表: 下載文件 regular-expressions-cheat-sheet-v2.pdf (647.55 KB)
Linux+认证书籍: 下載文件 McGraw.Hill.Linux.plus.Certification.Study Guide.pdf (28.60 MB)
下載文件 O'Reilly.Bash.Cookbook.pdf (3.16 MB)
下載文件 A Practical Guide to Linux Commands, Edi ... (3.61 MB)
Oracle
Oracle9i OCP官方培训教程:
下載文件 sql.zip (3.34 MB)
下載文件 dba1.zip (1.78 MB)
下載文件 dba2.zip (2.95 MB)
下載文件 Perf.zip (6.90 MB)
Oracle 10教程:
下載文件 Oracle.Database.10g.Administration.Workshop.II.Student.Guide.pdf (4.74 MB)
下載文件 Oracle.Database.10g.Administration.Workshop.I.Student.Guide.pdf (5.66 MB)
下載文件 Sybex.OCA.Oracle.10g.Administration.I.Study.Guide.pdf (18.20 MB)
下載文件 Sybex.OCP.Oracle.10g.Administration.II.Study.Guide.pdf (15.39 MB)
Oracle 11g官方培训教程:
下載文件 d49996gc10_ppt Oracle Database 11g SQL Fundamentals I.rar (2.26 MB)
下載文件 d49994gc10_ppt Oracle Database 11g SQL Fundamentals II.rar (1.78 MB)
下載文件 d50102gc10_ppt Oracle Database 11g Administration Workshop I.rar (11.00 MB)
下載文件 d50079gc10_ppt Oracle Database 11g Administration Workshop II.rar (6.31 MB)
下載文件 d50317gc10_ppt Oracle Database 11g Performance Tuning.rar (3.63 MB)
英文版: 下載文件 d50081gc10_ppt Oracle Database 11g New Features for Administrators.rar(6.64 MB)
中文版: 下載文件 d50081cn11_ppt Oracle Database 11g - New Features for Administrators.rar (6.58 MB)
下載文件 d46592gc11_ppt Oracle Database 10g Managing Oracle on Linux for System Administrators.rar (1.25 MB)
下載文件 d50311gc10_ppt Oracle Database 11g RAC Administration.rar (7.80 MB)
下載文件 Oracle Database 10g.chm (2.43 MB)
下載文件 ORACLE.10G入门与实践.pdf (39.58 MB)
下載文件 Oracle.Database.10g实用培训教程.pdf (47.49 MB)
下載文件 精通ORACLE.10G备份与恢复.pdf (23.90 MB)
Python
BASIC:
A Byte of Python(Python 3.0) 下載文件 A Byte of Python.pdf (564.61 KB)
A Byte of Python中文版 下載文件 Python简明教程.pdf (784.85 KB)
下載文件 Dive into Python.zip (763.71 KB)
下載文件 Dive into Python 中文版.zip (3.51 MB)
下載文件 Python Essential Reference 4th Edition.pdf (4.80 MB)
下載文件 Python精要参考.pdf (678.65 KB)
下載文件 Learning Python.pdf (4.80 MB)
下載文件 Core Python Programming 2nd Edition.chm (3.45 MB)
高清完整版 下載文件 Python核心编程第二版.pdf (5.16 MB)
下載文件 Python Standard Library.chm (355.63 KB)
下載文件 Python Standard Library中文版.pdf (1.00 MB)
下載文件 Python Cookbook.chm (1.00 MB)
下載文件 Python Cookbook Collection.chm (2.53 MB)
Guido 2007年Python大会ppt,关于python3.0新特性 下載文件 Py3k2007PyCon.ppt (134.00 KB)
GUI:
下載文件 wxPython In Action.rar (9.24 MB)
wxPython in Action中文版 下載文件 wxPython实战(中文版).pdf (3.54 MB)
下載文件 wxPythonInAction_src.zip (333.41 KB)
WEB:
Django Book 收费版 下載文件 The Definitive Guide to Django 2nd Edition.pdf (5.92 MB)
下載文件 Practical Django Projects 2nd Edition.pdf (4.89 MB)
GAE:
下載文件 Google App Engine 入门.pdf (227.23 KB)
下載文件 Google App Engine 开发人员指南.pdf (855.70 KB)
下載文件 Using Google App Engine.pdf (3.20 MB)
下載文件 Developing With Google App Engine.pdf (3.35 MB)
Other:
下載文件 Twisted Network Programming Essentials Python.chm (1.24 MB)
下載文件 Python for Unix and Linux System Administration.pdf (3.41 MB)
下載文件 Text Processing in Python.chm (871.68 KB)
下載文件 Python Programming on Win32.chm (2.10 MB)
下載文件 Jython for Java Programmers.chm (713.20 KB)
English
下載文件 古典 1677超核心词表.pdf (1.34 MB)
下載文件 古典 1677超核心词表.rm (3.41 MB)
下載文件 新东方李玉技老师的734条高频词组.pdf (77.00 KB)
下載文件 英语常用短语词典.chm (2.31 MB)
Perl
下載文件 Perl Cook Book.pdf (9.22 MB)
英文版: 下載文件 Learning.Perl.4ed.En.chm (699.96 KB)
中文版: 下載文件 Learning.Perl.4ed.Cn.pdf (1.19 MB)
一本讲用perl进行automation测试的好书: 下載文件 Perl Testing.chm (640.57 KB)
Other
下載文件 Agile Web Development with Rails 3rdEdition.pdf (10.87 MB)
谭浩强那本: 下載文件 C语言程序设计.pdf (9.95 MB)
下載文件 C语言趣味编程百例.pdf (4.72 MB)
下載文件 数据库系统概论(第三版).pdf (10.16 MB)
下載文件 php5手册.chm (5.70 MB)
精通正则表达式: 下載文件 Mastering Regular Expressions.chm (1.45 MB)
- 09:16
- 浏览 (25526)
- 评论 (153)
- 分类: Java
- 收藏
2010
-
01
-
14
缩略显示
[置顶] 一个程序员的多年珍藏(python)
文章分类:Python编程
程序员珍藏的东西会是什么?呵呵,除了平时写的代码,就是那些百看不厌的电子书了。
昨天很郁闷,我用了5年的移动硬盘,莫名奇妙的坏掉了。里面40G的资料全部报销了。
为了不再重蹈覆辙,我决定把重要的电子书都放到网络硬盘上去备份。索性将这些资料的下载方式公布出来,与大家分享,一定会有你想要的!
Java Linux Oracle Perl相关的资料请看:http://jythoner.javaeye.com/blog/570792
BASIC:
A Byte of Python(Python 3.0) 下載文件 A Byte of Python.pdf (564.61 KB)
A Byte of Python中文版 下載文件 Python简明教程.pdf (784.85 KB)
下載文件 Dive into Python.zip (763.71 KB)
下載文件 Dive into Python 中文版.zip (3.51 MB)
下載文件 Python Essential Reference 4th Edition.pdf (4.80 MB)
下載文件 Python精要参考.pdf (678.65 KB)
下載文件 Learning Python.pdf (4.80 MB)
下載文件 Core Python Programming 2nd Edition.chm (3.45 MB)
高清完整版 下載文件 Python核心编程第二版.pdf (5.16 MB)
下載文件 Python Standard Library.chm (355.63 KB)
下載文件 Python Standard Library中文版.pdf (1.00 MB)
下載文件 Python Cookbook.chm (1.00 MB)
下載文件 Python Cookbook Collection.chm (2.53 MB)
Guido 2007年Python大会ppt,关于python3.0新特性 下載文件 Py3k2007PyCon.ppt (134.00 KB)
GUI:
下載文件 wxPython In Action.rar (9.24 MB)
wxPython in Action中文版 下載文件 wxPython实战(中文版).pdf (3.54 MB)
下載文件 wxPythonInAction_src.zip (333.41 KB)
WEB:
Django Book 收费版 下載文件 The Definitive Guide to Django 2nd Edition.pdf (5.92 MB)
下載文件 Practical Django Projects 2nd Edition.pdf (4.89 MB)
GAE:
下載文件 Google App Engine 入门.pdf (227.23 KB)
下載文件 Google App Engine 开发人员指南.pdf (855.70 KB)
下載文件 Using Google App Engine.pdf (3.20 MB)
下載文件 Developing With Google App Engine.pdf (3.35 MB)
Other:
下載文件 Twisted Network Programming Essentials Python.chm (1.24 MB)
下載文件 Python for Unix and Linux System Administration.pdf (3.41 MB)
下載文件 Text Processing in Python.chm (871.68 KB)
下載文件 Python Programming on Win32.chm (2.10 MB)
下載文件 Jython for Java Programmers.chm (713.20 KB)
- 12:07
- 浏览 (6689)
- 评论 (26)
- 分类: Java
- 收藏
2010
-
01
-
05
缩略显示
网站架构(页面静态化,图片服务器分离,负载均衡)方案全解析
文章分类:综合技术
1、HTML静态化其实大家都知道,效率最高、消耗最小的就是纯静态化的html页面,所以我们尽可能使我们的网站上的页面采用静态页面来实现,这个最简单的方法其实也是最有效的方法。但是对于大量内容并且频繁更新的网站,我们无法全部手动去挨个实现,于是出现了我们常见的信息发布系统CMS,像我们常访问的各个门户站点的新闻频道,甚至他们的其他频道,都是通过信息发布系统来管理和实现的,信息发布系统可以实现最简单的信息录入自动生成静态页面,还能具备频道管理、权限管理、自动抓取等功能,对于一个大型网站来说,拥有一套高效、可管理的CMS是必不可少的。除了门户和信息发布类型的网站,对于交互性要求很高的社区类型网站来说,尽可能的静态化也是提高性能的必要手段,将社区内的帖子、文章进行实时的静态化,有更新的时候再重新静态化也是大量使用的策略,像Mop的大杂烩就是使用了这样的策略,网易社区等也是如此。同时,html静态化也是某些缓存策略使用的手段,对于系统中频繁使用数据库查询但是内容更新很小的应用,可以考虑使用html静态化来实现,比如论坛中论坛的公用设置信息,这些信息目前的主流论坛都可以进行后台管理并且存储再数据库中,这些信息其实大量被前台程序调用,但是更新频率很小,可以考虑将这部分内容进行后台更新的时候进行静态化,这样避免了大量的数据库访问请求。
2、图片服务器分离大家知道,对于Web服务器来说,不管是Apache、IIS还是其他容器,图片是最消耗资源的,于是我们有必要将图片与页面进行分离,这是基本上大型网站都会采用的策略,他们都有独立的图片服务器,甚至很多台图片服务器。这样的架构可以降低提供页面访问请求的服务器系统压力,并且可以保证系统不会因为图片问题而崩溃,在应用服务器和图片服务器上,可以进行不同的配置优化,比如apache在配置ContentType的时候可以尽量少支持,尽可能少的LoadModule,保证更高的系统消耗和执行效率。
3、数据库集群和库表散列大型网站都有复杂的应用,这些应用必须使用数据库,那么在面对大量访问的时候,数据库的瓶颈很快就能显现出来,这时一台数据库将很快无法满足应用,于是我们需要使用数据库集群或者库表散列。在数据库集群方面,很多数据库都有自己的解决方案,Oracle、Sybase等都有很好的方案,常用的MySQL提供的Master/Slave也是类似的方案,您使用了什么样的DB,就参考相应的解决方案来实施即可。上面提到的数据库集群由于在架构、成本、扩张性方面都会受到所采用DB类型的限制,于是我们需要从应用程序的角度来考虑改善系统架构,库表散列是常用并且最有效的解决方案。我们在应用程序中安装业务和应用或者功能模块将数据库进行分离,不同的模块对应不同的数据库或者表,再按照一定的策略对某个页面或者功能进行更小的数据库散列,比如用户表,按照用户ID进行表散列,这样就能够低成本的提升系统的性能并且有很好的扩展性。sohu的论坛就是采用了这样的架构,将论坛的用户、设置、帖子等信息进行数据库分离,然后对帖子、用户按照板块和ID进行散列数据库和表,最终可以在配置文件中进行简单的配置便能让系统随时增加一台低成本的数据库进来补充系统性能。
4、缓存缓存一词搞技术的都接触过,很多地方用到缓存。网站架构和网站开发中的缓存也是非常重要。这里先讲述最基本的两种缓存。高级和分布式的缓存在后面讲述。架构方面的缓存,对Apache比较熟悉的人都能知道Apache提供了自己的缓存模块,也可以使用外加的Squid模块进行缓存,这两种方式均可以有效的提高Apache的访问响应能力。网站程序开发方面的缓存,Linux上提供的Memory Cache是常用的缓存接口,可以在web开发中使用,比如用Java开发的时候就可以调用MemoryCache对一些数据进行缓存和通讯共享,一些大型社区使用了这样的架构。另外,在使用web语言开发的时候,各种语言基本都有自己的缓存模块和方法,PHP有Pear的Cache模块,Java就更多了,.net不是很熟悉,相信也肯定有。
5、镜像镜像是大型网站常采用的提高性能和数据安全性的方式,镜像的技术可以解决不同网络接入商和地域带来的用户访问速度差异,比如 ChinaNet和EduNet之间的差异就促使了很多网站在教育网内搭建镜像站点,数据进行定时更新或者实时更新。在镜像的细节技术方面,这里不阐述太深,有很多专业的现成的解决架构和产品可选。也有廉价的通过软件实现的思路,比如Linux上的rsync等工具。
6、负载均衡负载均衡将是大型网站解决高负荷访问和大量并发请求采用的终极解决办法。负载均衡技术发展了多年,有很多专业的服务提供商和产品可以选择,我个人接触过一些解决方法,其中有两个架构可以给大家做参考。
7、硬件四层交换第四层交换使用第三层和第四层信息包的报头信息,根据应用区间识别业务流,将整个区间段的业务流分配到合适的应用服务器进行处理。 第四层交换功能就象是虚 IP,指向物理服务器。它传输的业务服从的协议多种多样,有HTTP、FTP、NFS、Telnet或其他协议。这些业务在物理服务器基础上,需要复杂的载量平衡算法。在IP世界,业务类型由终端TCP或UDP端口地址来决定,在第四层交换中的应用区间则由源端和终端IP地址、TCP和UDP端口共同决定。在硬件四层交换产品领域,有一些知名的产品可以选择,比如Alteon、F5等,这些产品很昂贵,但是物有所值,能够提供非常优秀的性能和很灵活的管理能力。Yahoo中国当初接近2000台服务器使用了三四台Alteon就搞定了
。8、软件四层交换大家知道了硬件四层交换机的原理后,基于OSI模型来实现的软件四层交换也就应运而生,这样的解决方案实现的原理一致,不过性能稍差。但是满足一定量的压力还是游刃有余的,有人说软件实现方式其实更灵活,处理能力完全看你配置的熟悉能力。软件四层交换我们可以使用Linux上常用的LVS来解决,LVS就是Linux Virtual Server,他提供了基于心跳线heartbeat的实时灾难应对解决方案,提高系统的鲁棒性,同时可供了灵活的虚拟VIP配置和管理功能,可以同时满足多种应用需求,这对于分布式的系统来说必不可少。一个典型的使用负载均衡的策略就是,在软件或者硬件四层交换的基础上搭建squid集群,这种思路在很多大型网站包括搜索引擎上被采用,这样的架构低成本、高性能还有很强的扩张性,随时往架构里面增减节点都非常容易。这样的架构我准备空了专门详细整理一下和大家探讨。对于大型网站来说,前面提到的每个方法可能都会被同时使用到,我这里介绍得比较浅显,具体实现过程中很多细节还需要大家慢慢熟悉和体会,有时一个很小的squid参数或者apache参数设置,对于系统性能的影响就会很大,希望大家一起讨论,达到抛砖引玉之效。
用squid做web cache server,而apache在squid的后面提供真正的web服务。当然使用这样的架构必须要保证主页上大部分都是静态页面。这就需要程序员的配合将页面在反馈给客户端之前将页面全部转换成静态页面。
基本看出sina和sohu对于频道等栏目都用了相同的技术,即squid来监听这些IP的80端口,而真正的web server来监听另外一个端口。从用户的感觉上来说不会有任何的区别,而相对于将web server直接和客户端连在一起的方式,这样的方式明显的节省的带宽和服务器。用户访问的速度感觉也会更快。
http://www.dbanotes.net/arch/yupoo_arch.html
带宽:4000M/S (参考)
服务器数量:60 台左右
Web服务器:Lighttpd, Apache, nginx
应用服务器:Tomcat
其他:Python, Java, MogileFS 、ImageMagick 等
关于 Squid 与 Tomcat
Squid 与 Tomcat 似乎在 Web 2.0 站点的架构中较少看到。我首先是对 Squid 有点疑问,对此阿华的解释是"目前暂时还没找到效率比 Squid 高的缓存系统,原来命中率的确很差,后来在 Squid 前又装了层 Lighttpd, 基于 url 做 hash, 同一个图片始终会到同一台 squid 去,所以命中率彻底提高了"
对于应用服务器层的 Tomcat,现在 Yupoo! 技术人员也在逐渐用其他轻量级的东西替代,而 YPWS/YPFS 现在已经用 Python 进行开发了。
名次解释:
· YPWS--Yupoo Web Server YPWS 是用 Python开发的一个小型 Web 服务器,提供基本的 Web 服务外,可以增加针对用户、图片、外链网站显示的逻辑判断,可以安装于任何有空闲资源的服务器中,遇到性能瓶颈时方便横向扩展。
· YPFS--Yupoo File System 与 YPWS 类似,YPFS 也是基于这个 Web 服务器上开发的图片上传服务器。
【Updated: 有网友留言质疑 Python 的效率,Yupoo 老大刘平阳在 del.icio.us 上写到 "YPWS用Python自己写的,每台机器每秒可以处理294个请求, 现在压力几乎都在10%以下"】
图片处理层
接下来的 Image Process Server 负责处理用户上传的图片。使用的软件包也是 ImageMagick,在上次存储升级的同时,对于锐化的比率也调整过了(我个人感觉,效果的确好了很多)。”Magickd“ 是图像处理的一个远程接口服务,可以安装在任何有空闲 CPU资源的机器上,类似 Memcached的服务方式。
我们知道 Flickr 的缩略图功能原来是用 ImageMagick 软件包的,后来被雅虎收购后出于版权原因而不用了(?);EXIF 与 IPTC Flicke 是用 Perl 抽取的,我是非常建议 Yupoo! 针对 EXIF 做些文章,这也是潜在产生受益的一个重点。
图片存储层
原来 Yupoo! 的存储采用了磁盘阵列柜,基于 NFS 方式的,随着数据量的增大,”Yupoo! 开发部从07年6月份就开始着手研究一套大容量的、能满足 Yupoo! 今后发展需要的、安全可靠的存储系统“,看来 Yupoo! 系统比较有信心,也是满怀期待的,毕竟这要支撑以 TB 计算的海量图片的存储和管理。我们知道,一张图片除了原图外,还有不同尺寸的,这些图片统一存储在 MogileFS 中。
对于其他部分,常见的 Web 2.0 网站必须软件都能看到,如 MySQL、Memcached 、Lighttpd 等。Yupoo! 一方面采用不少相对比较成熟的开源软件,一方面也在自行开发定制适合自己的架构组件。这也是一个 Web 2.0 公司所必需要走的一个途径。
非常感谢一下 Yupoo! 阿华对于技术信息的分享,技术是共通的。下一个能爆料是哪家?
--EOF--
lighttpd+squid这套缓存是放在另外一个机房作为cdn的一个节点使用的,图中没描绘清楚,给大家带来不便了。
squid前端用lighttpd没用nginx,主要是用了这么久,没出啥大问题,所以就没想其他的了。
URL Hash的扩展性的确不好,能做的就是不轻易去增减服务器,我们目前是5台服务器做一组hash.
我们现在用Python写的Web Server,在效率方面,我可以给个测试数据,根据目前的访问日志模拟访问测试的结果是1台ypws,平均每秒处理294个请求(加载所有的逻辑判断)。
在可靠性上,还不没具体的数据,目前运行1个多月还没有任何异常。
lvs每个节点上都装nginx,主要是为了反向代理及处理静态内容,不过apache已显得不是那么必需,准备逐渐去掉。
我们处理图片都是即时的,我们目前半数以上的服务器都装了magickd服务,用来分担图片处理请求。
http://www.dbanotes.net/review/tailrank_arch.html
每天数以千万计的 Blog 内容中,实时的热点是什么? Tailrank 这个 Web 2.0 Startup 致力于回答这个问题。
专门爆料网站架构的 Todd Hoff 对 Kevin Burton 进行了采访。于是我们能了解一下 Tailrank 架构的一些信息。每小时索引 2400 万的 Blog 与 Feed,内容处理能力为 160-200Mbps,IO 写入大约在10-15MBps。每个月要处理 52T 之多的原始数据。Tailrank 所用的爬虫现在已经成为一个独立产品:spinn3r。
服务器硬件
目前大约 15 台服务器,CPU 是 64 位的 Opteron。每台主机上挂两个 SATA 盘,做 RAID 0。据我所知,国内很多 Web 2.0 公司也用的是类似的方式,SATA 盘容量达,低廉价格,堪称不二之选。操作系统用的是 Debian Linux 。Web 服务器用 Apache 2.0,Squid 做反向代理服务器。
数据库
Tailrank 用 MySQL 数据库,联邦数据库形式。存储引擎用 InnoDB, 数据量 500GB。Kevin Burton 也指出了 MySQL 5 在修了一些 多核模式下互斥锁的问题(This Bug?)。到数据库的JDBC 驱动连接池用 lbpool 做负载均衡。MySQL Slave 或者 Master的复制用 MySQLSlaveSync 来轻松完成。不过即使这样,还要花费 20%的时间来折腾 DB。
其他开放的软件
任何一套系统都离不开合适的 Profiling 工具,Tailrank 也不利外,针对 Java 程序的 Benchmark 用 Benchmark4j。Log 工具用 Log5j(不是 Log4j)。Tailrank 所用的大部分工具都是开放的。
Tailrank 的一个比较大的竞争对手是 Techmeme,虽然二者暂时看面向内容的侧重点有所不同。其实,最大的对手还是自己,当需要挖掘的信息量越来越大,如果精准并及时的呈现给用户内容的成本会越来越高。从现在来看,Tailrank 离预期目标还差的很远。期待罗马早日建成
YouTube架构学习
关键字: YouTube
原文: YouTube Architecture
YouTube发展迅速,每天超过1亿的视频点击量,但只有很少人在维护站点和确保伸缩性。
平台
Apache
Python
Linux(SuSe)
MySQL
psyco,一个动态的Python到C的编译器
lighttpd代替Apache做视频查看
状态
支持每天超过1亿的视频点击量
成立于2005年2月
于2006年3月达到每天3千万的视频点击量
于2006年7月达到每天1亿的视频点击量
2个系统管理员,2个伸缩性软件架构师
2个软件开发工程师,2个网络工程师,1个DBA
处理飞速增长的流量
Java代码
1. while (true)
2. {
3. identify_and_fix_bottlenecks();
4. drink();
5. sleep();
6. notice_new_bottleneck();
7. }
while (true)
{
identify_and_fix_bottlenecks();
drink();
sleep();
notice_new_bottleneck();
}
每天运行该循环多次
Web服务器
1,NetScaler用于负载均衡和静态内容缓存
2,使用mod_fast_cgi运行Apache
3,使用一个Python应用服务器来处理请求的路由
4,应用服务器与多个数据库和其他信息源交互来获取数据和格式化html页面
5,一般可以通过添加更多的机器来在Web层提高伸缩性
6,Python的Web层代码通常不是性能瓶颈,大部分时间阻塞在RPC
7,Python允许快速而灵活的开发和部署
8,通常每个页面服务少于100毫秒的时间
9,使用psyco(一个类似于JIT编译器的动态的Python到C的编译器)来优化内部循环
10,对于像加密等密集型CPU活动,使用C扩展
11,对于一些开销昂贵的块使用预先生成并缓存的html
12,数据库里使用行级缓存
13,缓存完整的Python对象
14,有些数据被计算出来并发送给各个程序,所以这些值缓存在本地内存中。这是个使用不当的策略。应用服务器里最快的缓存将预先计算的值发送给所有服务器也花不了多少时间。只需弄一个代理来监听更改,预计算,然后发送。
视频服务
1,花费包括带宽,硬件和能源消耗
2,每个视频由一个迷你集群来host,每个视频被超过一台机器持有
3,使用一个集群意味着:
-更多的硬盘来持有内容意味着更快的速度
-failover。如果一台机器出故障了,另外的机器可以继续服务
-在线备份
4,使用lighttpd作为Web服务器来提供视频服务:
-Apache开销太大
-使用epoll来等待多个fds
-从单进程配置转变为多进程配置来处理更多的连接
5,大部分流行的内容移到CDN:
-CDN在多个地方备份内容,这样内容离用户更近的机会就会更高
-CDN机器经常内存不足,因为内容太流行以致很少有内容进出内存的颠簸
6,不太流行的内容(每天1-20浏览次数)在许多colo站点使用YouTube服务器
-长尾效应。一个视频可以有多个播放,但是许多视频正在播放。随机硬盘块被访问
-在这种情况下缓存不会很好,所以花钱在更多的缓存上可能没太大意义。
-调节RAID控制并注意其他低级问题
-调节每台机器上的内存,不要太多也不要太少
视频服务关键点
1,保持简单和廉价
2,保持简单网络路径,在内容和用户间不要有太多设备
3,使用常用硬件,昂贵的硬件很难找到帮助文档
4,使用简单而常见的工具,使用构建在Linux里或之上的大部分工具
5,很好的处理随机查找(SATA,tweaks)
缩略图服务
1,做到高效令人惊奇的难
2,每个视频大概4张缩略图,所以缩略图比视频多很多
3,缩略图仅仅host在几个机器上
4,持有一些小东西所遇到的问题:
-OS级别的大量的硬盘查找和inode和页面缓存问题
-单目录文件限制,特别是Ext3,后来移到多分层的结构。内核2.6的最近改进可能让Ext3允许大目录,但在一个文件系统里存储大量文件不是个好主意
-每秒大量的请求,因为Web页面可能在页面上显示60个缩略图
-在这种高负载下Apache表现的非常糟糕
-在Apache前端使用squid,这种方式工作了一段时间,但是由于负载继续增加而以失败告终。它让每秒300个请求变为20个
-尝试使用lighttpd但是由于使用单线程它陷于困境。遇到多进程的问题,因为它们各自保持自己单独的缓存
-如此多的图片以致一台新机器只能接管24小时
-重启机器需要6-10小时来缓存
5,为了解决所有这些问题YouTube开始使用Google的BigTable,一个分布式数据存储:
-避免小文件问题,因为它将文件收集到一起
-快,错误容忍
-更低的延迟,因为它使用分布式多级缓存,该缓存与多个不同collocation站点工作
-更多信息参考Google Architecture,GoogleTalk Architecture和BigTable
数据库
1,早期
-使用MySQL来存储元数据,如用户,tags和描述
-使用一整个10硬盘的RAID 10来存储数据
-依赖于信用卡所以YouTube租用硬件
-YouTube经过一个常见的革命:单服务器,然后单master和多read slaves,然后数据库分区,然后sharding方式
-痛苦与备份延迟。master数据库是多线程的并且运行在一个大机器上所以它可以处理许多工作,slaves是单线程的并且通常运行在小一些的服务器上并且备份是异步的,所以slaves会远远落后于master
-更新引起缓存失效,硬盘的慢I/O导致慢备份
-使用备份架构需要花费大量的money来获得增加的写性能
-YouTube的一个解决方案是通过把数据分成两个集群来将传输分出优先次序:一个视频查看池和一个一般的集群
2,后期
-数据库分区
-分成shards,不同的用户指定到不同的shards
-扩散读写
-更好的缓存位置意味着更少的IO
-导致硬件减少30%
-备份延迟降低到0
-现在可以任意提升数据库的伸缩性
数据中心策略
1,依赖于信用卡,所以最初只能使用受管主机提供商
2,受管主机提供商不能提供伸缩性,不能控制硬件或使用良好的网络协议
3,YouTube改为使用colocation arrangement。现在YouTube可以自定义所有东西并且协定自己的契约
4,使用5到6个数据中心加CDN
5,视频来自任意的数据中心,不是最近的匹配或其他什么。如果一个视频足够流行则移到CDN
6,依赖于视频带宽而不是真正的延迟。可以来自任何colo
7,图片延迟很严重,特别是当一个页面有60张图片时
8,使用BigTable将图片备份到不同的数据中心,代码查看谁是最近的
学到的东西
1,Stall for time。创造性和风险性的技巧让你在短期内解决问题而同时你会发现长期的解决方案
2,Proioritize。找出你的服务中核心的东西并对你的资源分出优先级别
3,Pick your battles。别怕将你的核心服务分出去。YouTube使用CDN来分布它们最流行的内容。创建自己的网络将花费太多时间和太多money
4,Keep it simple!简单允许你更快的重新架构来回应问题
5,Shard。Sharding帮助隔离存储,CPU,内存和IO,不仅仅是获得更多的写性能
6,Constant iteration on bottlenecks:
-软件:DB,缓存
-OS:硬盘I/O
-硬件:内存,RAID
7,You succeed as a team。拥有一个跨越条律的了解整个系统并知道系统内部是什么样的团队,如安装打印机,安装机器,安装网络等等的人。With a good team all things are possible。
http://hideto.javaeye.com/blog/130815
Google架构学习
关键字: Google
原文:Google Architecture
Google是伸缩性的王者。Google一直的目标就是构建高性能高伸缩性的基础组织来支持它们的产品。
平台
Linux
大量语言:Python,Java,C++
状态
在2006年大约有450,000台廉价服务器
在2005年Google索引了80亿Web页面,现在没有人知道数目
目前在Google有超过200个GFS集群。一个集群可以有1000或者甚至5000台机器。成千上万的机器从运行着5000000000000000字节存储的GFS集群获取数据,集群总的读写吞吐量可以达到每秒40兆字节
目前在Google有6000个MapReduce程序,而且每个月都写成百个新程序
BigTable伸缩存储几十亿的URL,几百千千兆的卫星图片和几亿用户的参数选择
堆栈
Google形象化它们的基础组织为三层架构:
1,产品:搜索,广告,email,地图,视频,聊天,博客
2,分布式系统基础组织:GFS,MapReduce和BigTable
3,计算平台:一群不同的数据中心里的机器
4,确保公司里的人们部署起来开销很小
5,花费更多的钱在避免丢失日志数据的硬件上,其他类型的数据则花费较少
可信赖的存储机制GFS(Google File System)
1,可信赖的伸缩性存储是任何程序的核心需求。GFS就是Google的核心存储平台
2,Google File System - 大型分布式结构化日志文件系统,Google在里面扔了大量的数据
3,为什么构建GFS而不是利用已有的东西?因为可以自己控制一切并且这个平台与别的不一样,Google需要:
-跨数据中心的高可靠性
-成千上万的网络节点的伸缩性
-大读写带宽的需求
-支持大块的数据,可能为上千兆字节
-高效的跨节点操作分发来减少瓶颈
4,系统有Master和Chunk服务器
-Master服务器在不同的数据文件里保持元数据。数据以64MB为单位存储在文件系统中。客户端与Master服务器交流来在文件上做元数据操作并且找到包含用户需要数据的那些Chunk服务器
-Chunk服务器在硬盘上存储实际数据。每个Chunk服务器跨越3个不同的Chunk服务器备份以创建冗余来避免服务器崩溃。一旦被Master服务器指明,客户端程序就会直接从Chunk服务器读取文件
6,一个上线的新程序可以使用已有的GFS集群或者可以制作自己的GFS集群
7,关键点在于有足够的基础组织来让人们对自己的程序有所选择,GFS可以调整来适应个别程序的需求
使用MapReduce来处理数据
1,现在你已经有了一个很好的存储系统,你该怎样处理如此多的数据呢?比如你有许多TB的数据存储在1000台机器上。数据库不能伸缩或者伸缩到这种级别花费极大,这就是
MapReduce出现的原因
2,
MapReduce是一个处理和生成大量数据集的编程模型和相关实现。用户指定一个
map方法来处理一个键/值对来生成一个中间的键/值对,还有一个reduce方法来合并所有关联到同样的中间键的中间值。许多真实世界的任务都可以使用这种模型来表现。以这种风格来写的程序会自动并行的在一个大量机器的集群里运行。运行时系统照顾输入数据划分、程序在机器集之间执行的调度、机器失败处理和必需的内部机器交流等细节。这允许程序员没有多少并行和分布式系统的经验就可以很容易使用一个大型分布式系统资源
3,为什么使用
MapReduce?
-跨越大量机器分割任务的好方式
-处理机器失败
-可以与不同类型的程序工作,例如搜索和广告。几乎任何程序都有
map和reduce类型的操作。你可以预先计算有用的数据、查询字数统计、对TB的数据排序等等
4,
MapReduce系统有三种不同类型的服务器
-Master服务器分配用户任务到
Map和Reduce服务器。它也跟踪任务的状态
-
Map服务器接收用户输入并在其基础上处理
map操作。结果写入中间文件
-Reduce服务器接收
Map服务器产生的中间文件并在其基础上处理reduce操作
5,例如,你想在所有Web页面里的字数。你将存储在GFS里的所有页面抛入
MapReduce。这将在成千上万台机器上同时进行并且所有的调整、工作调度、失败处理和数据传输将自动完成
-步骤类似于:GFS ->
Map -> Shuffle -> Reduction -> Store Results back into GFS
-在
MapReduce里一个
map操作将一些数据映射到另一个中,产生一个键值对,在我们的例子里就是字和字数
-Shuffling操作聚集键类型
-Reduction操作计算所有键值对的综合并产生最终的结果
6,Google索引操作管道有大约20个不同的
map和reduction。
7,程序可以非常小,如20到50行代码
8,一个问题是掉队者。掉队者是一个比其他程序慢的计算,它阻塞了其他程序。掉队者可能因为缓慢的IO或者临时的CPU不能使用而发生。解决方案是运行多个同样的计算并且当一个完成后杀死所有其他的
9,数据在
Map和Reduce服务器之间传输时被压缩了。这可以节省带宽和I/O。
在BigTable里存储结构化数据
1,BigTable是一个大伸缩性、错误容忍、自管理的系统,它包含千千兆的内存和1000000000000000的存储。它可以每秒钟处理百万的读写
2,BigTable是一个构建于GFS之上的分布式哈希机制。它不是关系型数据库。它不支持join或者SQL类型查询
3,它提供查询机制来通过键访问结构化数据。GFS存储存储不透明的数据而许多程序需求有结构化数据
4,商业数据库不能达到这种级别的伸缩性并且不能在成千上万台机器上工作
5,通过控制它们自己的低级存储系统Google得到更多的控制权来改进它们的系统。例如,如果它们想让跨数据中心的操作更简单这个特性,它们可以内建它
6,系统运行时机器可以自由的增删而整个系统保持工作
7,每个数据条目存储在一个格子里,它可以通过一个行key和列key或者时间戳来访问
8,每一行存储在一个或多个tablet中。一个tablet是一个64KB块的数据序列并且格式为SSTable
9,BigTable有三种类型的服务器:
-Master服务器分配tablet服务器,它跟踪tablet在哪里并且如果需要则重新分配任务
-Tablet服务器为tablet处理读写请求。当tablet超过大小限制(通常是100MB-200MB)时它们拆开tablet。当一个Tablet服务器失败时,则100个Tablet服务器各自挑选一个新的tablet然后系统恢复。
-Lock服务器形成一个分布式锁服务。像打开一个tablet来写、Master调整和访问控制检查等都需要互斥
10,一个locality组可以用来在物理上将相关的数据存储在一起来得到更好的locality选择
11,tablet尽可能的缓存在RAM里
硬件
1,当你有很多机器时你怎样组织它们来使得使用和花费有效?
2,使用非常廉价的硬件
3,A 1,000-fold computer power increase can be had for a 33 times lower cost if you you use a failure-prone infrastructure rather than an infrastructure built on highly reliable components. You must build reliability on top of unreliability for this strategy to work.
4,Linux,in-house rack design,PC主板,低端存储
5,Price per wattage on performance basis isn't getting better. Have huge power and cooling issues
6,使用一些collocation和Google自己的数据中心
其他
1,迅速更改而不是等待QA
2,库是构建程序的卓越方式
3,一些程序作为服务提供
4,一个基础组织处理程序的版本,这样它们可以发布而不用害怕会破坏什么东西
Google将来的方向
1,支持地理位置分布的集群
2,为所有数据创建一个单独的全局名字空间。当前的数据由集群分离
3,更多和更好的自动化数据迁移和计算
4,解决当使用网络划分来做广阔区域的备份时的一致性问题(例如保持服务即使一个集群离线维护或由于一些损耗问题)
学到的东西
1,基础组织是有竞争性的优势。特别是对Google而言。Google可以很快很廉价的推出新服务,并且伸缩性其他人很难达到。许多公司采取完全不同的方式。许多公司认为基础组织开销太大。Google认为自己是一个系统工程公司,这是一个新的看待软件构建的方式
2,跨越多个数据中心仍然是一个未解决的问题。大部分网站都是一个或者最多两个数据中心。我们不得不承认怎样在一些数据中心之间完整的分布网站是很需要技巧的
3,如果你自己没有时间从零开始重新构建所有这些基础组织你可以看看Hadoop。Hadoop是这里很多同样的主意的一个开源实现
4,平台的一个优点是初级开发人员可以在平台的基础上快速并且放心的创建健全的程序。如果每个项目都需要发明同样的分布式基础组织的轮子,那么你将陷入困境因为知道怎样完成这项工作的人相对较少
5,协同工作不一直是掷骰子。通过让系统中的所有部分一起工作则一个部分的改进将帮助所有的部分。改进文件系统则每个人从中受益而且是透明的。如果每个项目使用不同的文件系统则在整个堆栈中享受不到持续增加的改进
6,构建自管理系统让你没必要让系统关机。这允许你更容易在服务器之间平衡资源、动态添加更大的容量、让机器离线和优雅的处理升级
7,创建可进化的基础组织,并行的执行消耗时间的操作并采取较好的方案
8,不要忽略学院。学院有许多没有转变为产品的好主意。Most of what Google has done has prior art, just not prior large scale deployment.
9,考虑压缩。当你有许多CPU而IO有限时压缩是一个好的选择。
http://blog.daviesliu.net/2006/09/09/010620/
Lighttpd+Squid+Apache搭建高效率Web服务器
架构原理
Apache通常是开源界的首选Web服务器,因为它的强大和可靠,已经具有了品牌效应,可以适用于绝大部分的应用场合。但是它的强大有时候却显得笨重,配置文件得让人望而生畏,高并发情况下效率不太高。而轻量级的Web服务器Lighttpd却是后起之秀,其静态文件的响应能力远高于 Apache,据说是Apache的2-3倍。Lighttpd的高性能和易用性,足以打动我们,在它能够胜任的领域,尽量用它。Lighttpd对 PHP的支持也很好,还可以通过Fastcgi方式支持其他的语言,比如Python。
毕竟Lighttpd是轻量级的服务器,功能上不能跟Apache比,某些应用无法胜任。比如Lighttpd还不支持缓存,而现在的绝大部分站点都是用程序生成动态内容,没有缓存的话即使程序的效率再高也很难满足大访问量的需求,而且让程序不停的去做同一件事情也实在没有意义。首先,Web程序是需要做缓存处理的,即把反复使用的数据做缓存。即使这样也还不够,单单是启动Web处理程序的代价就不少,缓存最后生成的静态页面是必不可少的。而做这个是 Squid的强项,它本是做代理的,支持高效的缓存,可以用来给站点做反向代理加速。把Squid放在Apache或者Lighttpd的前端来缓存 Web服务器生成的动态内容,而Web应用程序只需要适当地设置页面实效时间即可。
即使是大部分内容动态生成的网站,仍免不了会有一些静态元素,比如图片、JS脚本、CSS等等,将Squid放在Apache或者Lighttp 前端后,反而会使性能下降,毕竟处理HTTP请求是Web服务器的强项。而且已经存在于文件系统中的静态内容再在Squid中缓存一下,浪费内存和硬盘空间。因此可以考虑将Lighttpd再放在Squid的前面,构成 Lighttpd+Squid+Apache的一条处理链,Lighttpd在最前面,专门用来处理静态内容的请求,把动态内容请求通过proxy模块转发给Squid,如果Squid中有该请求的内容且没有过期,则直接返回给Lighttpd。新请求或者过期的页面请求交由Apache中Web程序来处理。经过Lighttpd和Squid的两级过滤,Apache需要处理的请求将大大减少,减少了Web应用程序的压力。同时这样的构架,便于把不同的处理分散到多台计算机上进行,由Lighttpd在前面统一把关。
在这种架构下,每一级都是可以进行单独优化的,比如Lighttpd可以采用异步IO方式,Squid可以启用内存来缓存,Apache可以启用MPM 等,并且每一级都可以使用多台机器来均衡负载,伸缩性很好。
- 08:31
- 浏览 (798)
- 评论 (0)
- 分类: Java
- 收藏
2009
-
10
-
31
缩略显示
Java基础学习笔记
文章分类:Java编程
1.Java语言的特点:面向对象,跨平台,多线程
2.Java运行环境:JVM+Java API
3.数据类型:
boolean 1
char 16
byte 8
short 16
int 32
long 64
float 32
double 64
4.面向对象:
封装:类
继承:单一继承
多态:重写(Overridding)与重载(Overloading)
在子类中,方法的参数个数和返回值都与父类相同,称为重写
在同一个类中,方法的参数不同,称为重载
5.作用域:
private 子类不能继承
default 如果不在同一包中,子类不能继承
protected
public
6.垃圾回收原理:有向图原则(另一种为计数器类型),可能会有内存泄漏,计数器类型与有向图类型相比:效率更高,但是精度偏低,因为它很难发现变量循环引用的问题
会有内存泄漏的代码:
Vector v=new Vector(10)
for (int i=0;i<10;i++){
Object o=new Object();
v.add(o);
o=null;
}
解决方法:
v=null;
7.栈与堆:原始数据类型存放在栈里,对象数据类型存放在堆中,栈中存放堆中的地址。
8.变量比较:==比较的是栈,原始数据类型相同,但是引用类型值不等,equals比较的是堆,特例是string,java.lang.String类是final类型的,因此不可以继承这个类、不能修改这个类。
9.变量复制:原始数据类型复制的是值,引用数据类型复制的是栈中的引用,所以当一个修改的时候,会影响另一个。对象复制:Object.clone()方法
10.引用传递和值传递:原始数据类型传递的是值,引用数据类型传递的是栈中的引用
11.异常:(Java.lang.Exception)检查时异常,(Java.lang.RuntimeException)运行时异常,((java.lang.Error)错误,检查时异常必须处理
12.集合:collection: set:HashSet TreeSet
list:ArrayList LinkedList Vector Stack
map:Hash
Map Tree
Map HashTable Properties
13.Set里的元素是不能重复的,什么方法来区分重复与否呢? 是用==还是
equals()? 它们有何区别?
Set里的元素是不能重复的,那么用iterator()方法来区分重复与否。equals()是判读两
个Set是否相等。
equals()和==方法决定引用值是否指向同一对象equals()在类中被覆盖,为的是当两个
分离的对象的内容和类型相配的话,返回真值
14.ArrayList, Vector, LinkedList的存储性能和特性
ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据
以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元
素移动等内存操作,所以索引数据快而插入数据慢,Vector由于使用了synchronized方
法(线程安全),通常性能上较ArrayList差,而LinkedList使用双向链表实现存储,按序
号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即
可,所以插入速度较快。
15、Hash
Map和Hashtable的区别。
Hash
Map是Hashtable的轻量级实现(非线程安全的实现),他们都完成了
Map接口,
主要区别在于Hash
Map允许空(null)键值(key),由于非线程安全,效率上可能高于
Hashtable。
Hash
Map允许将null作为一个entry的key或者value,而Hashtable不允许。
Hash
Map把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因为
contains方法容易让人引起误解。
Hashtable继承自Dictionary类,而Hash
Map是Java1.2引进的
Map interface的一个实现。
最大的不同是,Hashtable的方法是Synchronize的,而Hash
Map不是,在多个线程访问
Hashtable时,不需要自己为它的方法实现同步,而Hash
Map 就必须为之提供外同步。
Hashtable和Hash
Map采用的hash/rehash算法都大概一样,所以性能不会有很大的差异。
- 22:23
- 浏览 (477)
- 评论 (1)
- 分类: Java
- 收藏
2009
-
07
-
02
缩略显示
定时执行任务的三种方法
定时执行任务的三种方法:
1)java.util.Timer.
2)ServletContextListener.
3)org.springframework.scheduling.timer.ScheduledTimerTask
1)java.util.Timer
这个方法应该是最常用的,不过这个方法需要手工启动你的任务:
Timer timer=new Timer();
timer.schedule(new ListByDayTimerTask(),10000,86400000);
这里的ListByDayTimerTask类必须extends TimerTask里面的run()方法。
2)ServletContextListener
这个方法在web容器环境比较方便,这样,在web server启动后就可以自动运行该任务,不需要手工操作。
将ListByDayListener implements ServletContextListener接口,在contextInitialized方法中加入启动Timer的代码,在 contextDestroyed方法中加入cancel该Timer的代码;然后在web.xml中,加入listener:
<-listener>
<-listener-class>com.qq.customer.ListByDayListener
<-/listener>
3)org.springframework.scheduling.timer.ScheduledTimerTask如果你用spring,那么你不需要写Timer类了,在schedulingContext-timer.xml中加入下面的内容就可以了:
10000
86400000
以上内容转载自:http://dev.csdn.net/author/xtpdcsse/ec8e8080a5b04fa79e7d4828bc807d3f.html
下面是我的实现。
1)利用java.util.Timer. 代码如下
<1>StartThread.java
[java] view plain copy print ?
- package com.jview.main;
- import java.util.Date;
- import java.util.Timer;
- import java.util.TimerTask;
- import org.apache.log4j.Logger;
- public class StartThreadextends Thread {
- private static Logger logger = Logger.getLogger("StartThread");
- public static final int EXECUTE_CYC = 86400000;
- int startH = 9;
- int startM = 52;
- private Timer _timer ;
- private Date _statDate;
- private Date _nowDate;
- public StartThread(){
- _nowDate = new Date();
- _timer = new Timer();
- _statDate = new Date(_nowDate.getYear(),_nowDate.getMonth(),_nowDate.getDate(),startH,startM);
- }
- public void StartUp(){
- _timer.schedule(
- new TimerTask() {
- public void run()
- {
- logger.info("开始统计...");
- try {
- Class.forName("com.jview.stat.StatPlan").newInstance();
- } catch (InstantiationException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
-
- e.printStackTrace();
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- }
- },_statDate,EXECUTE_CYC);
- }
- public static void main(String[] args) {
- StartThread _statUp = new StartThread();
- _statUp.StartUp();
- }
- }
package com.jview.main;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.log4j.Logger;
public class StartThread extends Thread {
private static Logger logger = Logger.getLogger("StartThread");
public static final int EXECUTE_CYC = 86400000; //24*60*60*1000毫秒
int startH = 9;
int startM = 52;
private Timer _timer ;
private Date _statDate;
private Date _nowDate;
public StartThread(){
_nowDate = new Date();
_timer = new Timer();
_statDate = new Date(_nowDate.getYear(),_nowDate.getMonth(),_nowDate.getDate(),startH,startM);
}
public void StartUp(){
_timer.schedule(
new TimerTask() {
public void run()
{
logger.info("开始统计...");
try {
Class.forName("com.jview.stat.StatPlan").newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
},_statDate,EXECUTE_CYC);
}
public static void main(String[] args) {
StartThread _statUp = new StartThread();
_statUp.StartUp();
}
}
<2>StatPlan.java
[java] view plain copy print ?
- package com.jview.stat;
- import java.util.Calendar;
- import org.apache.log4j.Logger;
- public class StatPlan {
- private static Logger logger = Logger.getLogger("StatPlan");
- private int i = 0;
- private StatPlanService _sps ;
- public StatPlan(){
- _sps = new StatWeekPlan();
- statPlan();
- }
- public void statPlan(){
- Calendar _c = Calendar.getInstance();
- logger.info("stat plan ... 执行"+ i +"次,时间:"+_c.getTime());
- _sps.StatPlan();
- i++;
- for(int i = 0; i<9999;i++){
- if(i==0 || i==9998){
- logger.info(""+i);
- }
- }
- }
- }
package com.jview.stat;
import java.util.Calendar;
import org.apache.log4j.Logger;
public class StatPlan {
private static Logger logger = Logger.getLogger("StatPlan");
private int i = 0;
private StatPlanService _sps ;
public StatPlan(){
_sps = new StatWeekPlan();
statPlan();
}
public void statPlan(){
Calendar _c = Calendar.getInstance();
logger.info("stat plan ... 执行"+ i +"次,时间:"+_c.getTime());
_sps.StatPlan();
i++;
for(int i = 0; i<9999;i++){
if(i==0 || i== 9998){
logger.info(""+i);
}
}
}
}
<3>StatWeekPlan .java
[java] view plain copy print ?
- import org.apache.log4j.Logger;
- public class StatWeekPlanextends StatPlanService {
- private static Logger logger = Logger.getLogger("StatWeekPlan");
- public void StatPlan(){
- logger.info("this is statWeekPlan");
- }
- }
- <4>StatPlanService .java
- public class StatPlanService {
- public void StatPlan(){
- }
- }
import org.apache.log4j.Logger;
public class StatWeekPlan extends StatPlanService {
private static Logger logger = Logger.getLogger("StatWeekPlan");
public void StatPlan(){
logger.info("this is statWeekPlan");
}
}
<4>StatPlanService .java
public class StatPlanService {
public void StatPlan(){
}
}
2)ServletContextListener.实现
<1> SysStatListener .java
[java] view plain copy print ?
- import java.util.Date;
- import java.util.Timer;
- import java.util.TimerTask;
- import javax.servlet.ServletContextEvent;
- import javax.servlet.ServletContextListener;
- import org.apache.log4j.Logger;
- public class SysStatListenerimplements ServletContextListener{
- private static Logger logger = Logger.getLogger("ListByDayListener");
- private StatTask _sTask;
- public void contextDestroyed(ServletContextEvent scevent) {
- String status = "停止系统统计线程";
- scevent.getServletContext().log(status);
- logger.info(status);
- _sTask.shutDown();
- }
- public void contextInitialized(ServletContextEvent scevent) {
- String status = "启动系统统计线程";
- scevent.getServletContext().log(status);
- logger.info(status);
- _sTask = new StatTask();
- _sTask.startUp();
- }
- }
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.log4j.Logger;
public class SysStatListener implements ServletContextListener{
private static Logger logger = Logger.getLogger("ListByDayListener");
private StatTask _sTask;
public void contextDestroyed(ServletContextEvent scevent) {
String status = "停止系统统计线程";
scevent.getServletContext().log(status);
logger.info(status);
_sTask.shutDown();
}
public void contextInitialized(ServletContextEvent scevent) {
String status = "启动系统统计线程";
scevent.getServletContext().log(status);
logger.info(status);
_sTask = new StatTask();
_sTask.startUp();
}
}
<2> StatTask .java
[java] view plain copy print ?
- import java.util.Date;
- import java.util.Timer;
- import java.util.TimerTask;
- import org.apache.log4j.Logger;
- public class StatTaskextends Thread {
- private static Logger logger = Logger.getLogger("StartThread");
- public staticfinal int EXECUTE_CYC =86400000;
- int startH = 9;
- int startM = 52;
- private Timer _timer ;
- private Date _statDate;
- private Date _nowDate;
- public StatTask(){
- _nowDate = new Date();
- _timer = new Timer();
- _statDate = new Date(_nowDate.getYear(),_nowDate.getMonth(),_nowDate.getDate(),startH,startM);
- }
- public void startUp(){
- _timer.schedule(
- new TimerTask() {
- public void run()
- {
- logger.info("开始统计...");
- try {
- Class.forName("com.jview.stat.StatPlan").newInstance();
- } catch (InstantiationException e) {
-
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (ClassNotFoundException e) {
-
- e.printStackTrace();
- }
- }
- },_statDate,EXECUTE_CYC);
- }
- public void shutDown(){
- _timer.cancel();
- }
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.log4j.Logger;
public class StatTask extends Thread {
private static Logger logger = Logger.getLogger("StartThread");
public static final int EXECUTE_CYC = 86400000;
int startH = 9;
int startM = 52;
private Timer _timer ;
private Date _statDate;
private Date _nowDate;
public StatTask(){
_nowDate = new Date();
_timer = new Timer();
_statDate = new Date(_nowDate.getYear(),_nowDate.getMonth(),_nowDate.getDate(),startH,startM);
}
public void startUp(){
_timer.schedule(
new TimerTask() {
public void run()
{
logger.info("开始统计...");
try {
Class.forName("com.jview.stat.StatPlan").newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
},_statDate,EXECUTE_CYC);
}
public void shutDown(){
_timer.cancel();
}
<3>在web.xml中添加下面的内容(注:下面的内容放到
mapping>的后面)
com.jview.auto.stat.SysStatListener
- 22:58
- 浏览 (583)
- 评论 (0)
- 分类: Java
- 收藏
2009
-
03
-
31
缩略显示
13个代码注释的小技巧
这篇文章是由José M. Aguilar在他卓越的博客中以西班牙语的形式首发,其后Timm Martin在获得Aguilar先生的授权下,对该文章进行翻译、修改,并且在DevTopics上发布。
以下13个小技巧可以使得你的代码在长时间内依然能够保持容易理解和维护。
1. 对不同级别的代码进行注释
对于不同级别的代码块,要使用统一的方法来进行注释。例如:
对于每一个类,需要包含一段简明扼要的描述,作者和上一次修改的时间
对于每一个方法,需要包含这个方法的用途,功能,参数以及返回结果
当你在一个团队里面的时候,采用一套注释的标准是非常重要的。当然,使用一种大家都认可的注释约定和工具(例如C#的XML注释和Java的Javadoc)在一定程度上能推动这项任务。
2. 使用段落注释
首先把代码块分解成多个“段落”,每一个段落都执行单一的任务;然后在每一个“段落”开始之前添加注释,告诉阅读代码的人接下来的这段代码是干什么用的
// 检查所有记录都是正确的
foreach (Record record in records)
{
if (rec.checkStatus()==Status.OK)
{
. . .
}
}
// 现在开始进行处理
Context ctx = new ApplicationContext();
ctx.BeginTransaction();
. . .
3. 对齐注释行
对于那些在行末写有注释的代码,应该对齐注释行来使得方便阅读
const MAX_ITEMS = 10; // maximum number of packets
const MASK = 0x1F; // mask bit TCP
有些开发人员使用tab来对齐注释,而另外一些人会用空格来对齐。由于tab在不同的编辑器和集成开发环境中会有所不同,所以最佳的方法是使用空格来对齐注释行。
4. 不要侮辱阅读者的智慧
要避免没用的注释,例如
if (a == 5) //如果a等于5
counter = 0 //把counte设为0
这不单把时间浪费在写没用的注释上面,同时也在分散读者的注意力。
5. 要有礼貌
应当避免没有礼貌的注释,例如“要注意一些愚蠢的用户会输入一个负数”,或者“修正由菜鸟工程师写的愚蠢得可怜的代码而导致的副作用”。这样的注释对于代码的写注释的人来说并没有任何好处,同时你永远都不会知道将来这些注释会被谁来阅读,你的老板,一个客户或者是刚才被你数落的愚蠢得可怜的工程师。
6. 直截了当
不要在注释里面写过多的废话。避免在注释里面卖弄ASCII艺术,写笑话,作诗和过于冗长。简而言之就是保持注释的简单和直接。
7. 使用统一的风格
有些人觉得注释应该让非程序员也能看懂。另外一些人觉得注释需要面对的读者只是程序员。无论如何,正如Successful Strategies for Commenting Code中所说的,最重要的是注释的风格需要统一,并且总是面向相同的读者。就自己而论,我怀疑非程序员是否会去读代码,所以我觉得注释应该面向程序员来写。
8. 在内部使用特殊的标签
当你在一个团队里工作的时候,采用一组一致的标签能帮助不同的程序员沟通。例如,很多团队会采用“TODO”标签来表示一段尚未完成的代码
int Estimate(int x, int y)
{
// TODO: implement the calculations
return 0;
}
标签注释并不会解释代码,它们寻求注意或者是传递信息。但是如果适当地使用这种技术,要记住跟进这段代码并且完成该标签传递的任务。
9. 在写代码的同时添加注释
当你在写代码而且记忆犹新的同时就添加注释。如果等到项目后期才添加注释,会让你事倍功半。“我没有时间写注释”,“我的时间很紧迫”和“项目已经延迟了”,这些都是不写注释的常见借口。有些工程师觉最佳的解决方法是“注释先行”。例如:
public void ProcessOrder()
{
// Make sure the products are available
// Check that the customer is valid
// Send the order to the store
// Generate bill
}
10. 把自己想象为注释的读者(事实上就是如此)
当你正在给代码写注释的时候,不仅仅为日后维护你的代码的开发者考虑,同时也设想一下如果自己就是注释的读者。Phil Haack曾经说过:
“一旦一行代码被敲到文件中, 你就已经要开始维护那一行代码了。”
所以,我们自己就是好(或者坏)注释的第一个受益者(或者受害者)。
11. 更新代码的时候要更新注释
如果注释没有随着代码的修改而更新,那么这些注释将是毫无意义的。代码和注释需要同步,否则注释只会让维护代码的开发者更加痛苦。需要特别注意的是,一些重构的工具会自动更新代码,但是却没有自动更新注释,那么注释就自然而然地过期作废了。
12. 良好可读性代码是注释的金科玉律
对于很多开发者来说,一个基本的原则就是:让代码自己描述自己。虽然有人怀疑这是由不喜欢写注释的程序员所倡导的一场运动,但是无需解释的代码有很大的好处,这些代码更加容易理解甚至让注释变得没有必要。例如,在我的文章Fluid Interfaces中就给大家展示了什么是清晰的无需解释的代码。
Calculator calc = new Calculator();
calc.Set(0);
calc.Add(10);
calc.Multiply(2);
calc.Subtract(4);
Console.WriteLine( “Result: {0}”, calc.Get() );
在这个例子里面,注释就像是违反了第4条技巧那样,变得毫无必要。要写出可读性好的代码,你需要使用适当的命名方式(在经典的 Ottinger’s Rules中有阐述),保证恰当的缩进,并且采用编码风格指导。如果代码不遵守这条技巧,那么注释看起来就好像是为自己不好的代码的写道歉信一样。
13. 跟你的同事分享这些技巧
虽然从第10条技巧中我们已经知道了自己就是好注释的得益者,但是这些技巧对于所有的开发者来说都是很有帮助的,尤其是整个团队都有相同共识的情况下。因此,大方地跟你的同事去分享这些技巧,让我们写出更加容易理解和维护的代码。
- 08:43
- 浏览 (469)
- 评论 (0)
- 分类: Java
- 收藏
2009
-
03
-
10
缩略显示
log4j配置文件的含义
今天试着用了一下log4j来处理java中的日志,感觉良好,顺便记录一下log4j的配置文件log4j.properties各语句的含义。
这是一个数据库配置文件
#这是一个配置文件实例,PropertyConfigurator将使用这个文件 :
#声明一个appender变量名为JDBC
log4j.rootLogger=DEBUG, JDBC
#JDBC是一个JDBCAppender类,这个类可以写消息到数据库
log4j.appender.JDBC=com.benqguru.palau.log.jdbc.test.JDBCAppender
#1.连接数据库的数据库选项
log4j.appender.JDBC.url=jdbc:mysql://localhost:3306/logtest
log4j.appender.JDBC.username=root
log4j.appender.JDBC.password=
#2.指定你自己的JDBCConnectionHandler的连接器选项
log4j.appender.JDBC.connection_class=com.benqguru.palau.log.jdbc.test.MyConnectionHandler
#3.指定一个静态的SQL语句的SQL选项,这个语句将在每次消息事件发生时被执行
log4j.appender.JDBC.sql=INSERT INTO LOGTEST (id, msg, created_on, created_by) VALUES (1, @MSG@, sysdate, 'me')
#4. 指定数据库中一个表的表选项。
log4j.appender.JDBC.table=logtest
#5.描述表的重要列的列选项(非空列是必须被描述的)
log4j.appender.JDBC.columns=id_seq~EMPTY id~ID~MyIDHandler msg~MSG created_on~TIMESTAMP created_by~STATIC~Thomas Fenner
#6.定义消息布局器的布局器选项(可选)
log4j.appender.JDBC.layout=org.apache.log4j.PatternLayout
log4j.appender.JDBC.layout.ConversionPattern=%m
#7.定义消息事件缓冲器的大小的缓冲器选项(可选)
log4j.appender.JDBC.buffer_size=1
#8.定义自动提交的提交选项(可选)
log4j.appender.JDBC.docommit=N
##########下面是英文说明#############
#Date - %d{DATE}[slf5s.DATE]
#Priority - %p[slf5s.PRIORITY]
#NDC - %x[slf5s.NDC]
#Thread - %t[slf5s.THREAD]
#Category - %c[slf5s.CATEGORY]
#Location - %l[slf5s.LOCATION]
#Message - %m[slf5s.MESSAGE]
#
#log4j.appender.R.layout.ConversionPattern=[slf5s.start]%d{DATE}[slf5s.DATE]%n/
# %p[slf5s.PRIORITY]%n%x[slf5s.NDC]%n%t[slf5s.THREAD]%n/
# %c[slf5s.CATEGORY]%n%l[slf5s.LOCATION]%n%m[slf5s.MESSAGE]%n%n
##########下面是中文说明#############
#%m 输出代码中指定的消息
#%p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
#%r 输出自应用启动到输出该log信息耗费的毫秒数
#%c 输出所属的类目,通常就是所在类的全名
#%t 输出产生该日志事件的线程名
#%n 输出一个回车换行符,Windows平台为“/r/n”,Unix平台为“/n”
#%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,
#比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921
#%l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)
这是一个普通的配置文件
#log4j会解析这个文件
log4j.debug=false
#暂时还不清楚这两个属性的作用
log4j.disableOverride=true
log4j.disable=INFO
#设置记录所有类的日志的优先级别
log4j.rootLogger=DEBUG,dest1,dest2
#设置这个包记录日志为假的话
#dist1,dist2就不会记录com.benqguru.commons.logging.test.LoggingSample的日志,只有dist3会记录.
#反之,会记录,这样就会重复记录
log4j.additivity.com.benqguru.commons.logging.test.LoggingSample=false
#特别指定某个特殊包的日志级别和目标设备
log4j.category.com.benqguru.commons.logging.test.LoggingSample=WARN, dest3
#这个目标设备用来debug
log4j.appender.dest1=org.apache.log4j.ConsoleAppender
#log4j.appender.dest1.layout=org.apache.log4j.SimpleLayout
log4j.appender.dest1.layout=org.apache.log4j.PatternLayout
#%-4r %-5p [%t] %37c %3x - %m%n
log4j.appender.dest1.layout.ConversionPattern=%d %p %c - <%m> (%F.%M:%L) %t%n
#这个目标设备用来trace
log4j.appender.dest2=org.apache.log4j.RollingFileAppender
#该文件记录日志的级别(INFO以下的级别不记录)
log4j.appender.dest2.Threshold=INFO
#文件保存路径
log4j.appender.dest2.File=c:/log4jlog.htm
#是否往文件追加信息
log4j.appender.dest2.Append=true
#设置文件最大值
log4j.appender.dest2.MaxFileSize=5KB
#设置备份文件的最大数量
log4j.appender.dest2.MaxBackupIndex=10
#使用一个html格式来记录日志
log4j.appender.dest2.layout=org.apache.log4j.HTMLLayout
#是否打印该消息的代码行
log4j.appender.dest2.layout.LocationInfo=true
#设置该日志的html的标题
log4j.appender.dest2.layout.Title=My app title
#这个目标设备用来trace指定类或包
log4j.appender.dest3=org.apache.log4j.DailyRollingFileAppender
#log4j.appender.dest3.Threshold=DEBUG
log4j.appender.dest3.File=c:/SpecPackageLog.htm
log4j.appender.dest3.Append=false
log4j.appender.dest3.layout=org.apache.log4j.HTMLLayout
log4j.appender.dest3.layout.LocationInfo=true
log4j.appender.dest3.layout.Title=My app title
- 13:37
- 浏览 (896)
- 评论 (2)
- 分类: Java
- 收藏
2009
-
03
-
10
缩略显示
Java Regex(Java正则表达式)
在Sun的API中对在对 “最大匹配Greedy”“最小匹配Reluctant”“完全匹配Possessive”的描述,不能让我明白他们有什么区别,现在将我对这三种匹配模式的理解写出来,供大家参考。
1、Greediness(贪心)匹配:
X?、X*、X+、X{n,}都是最大匹配。例如你要用“<.+>”去匹配“a
aava
abb”,也许你所期待的结果是想匹配“”,但是实际结果却会匹配到“
aava
”。这是为什么呢?下面我们跟踪下最大匹配的匹配过程。
①“<”匹配字符串的“<”。②“.+”匹配字符串的“tr>aava ab”,在进行最大匹配时,它把两个“>”都匹配了,它匹配了所有字符,直到文本的最后字符“b” ③这时,发现不能成功匹配“>”,开始按原路回退,用“a”与“>”匹配,直到“ab”前面的“>”匹配成功。
2、Reluctant(Laziness)最小匹配
X?、X*、X+、X{n,}都是最大匹配。好,加个?就成了Laziness匹配。例如X??、X*?、X+?、X{n,}?都是最小匹配,其实X{n,m}?和X{n }?有些多余。
最小匹配意味者,.+? 匹配一个字符后,马上试一试>的匹配可能,失败了,则.+? 再匹配一个字符,再马上试一试>的匹配可能。JDK文档中Greedy 和 Reluctant,它是以eat一口来隐喻的,所以翻译成贪吃和(勉强的)厌食最贴切了。不过我喜欢最大匹配、最小匹配的说法。
3、Possessive完全匹配
与最大匹配不同,还有一种匹配形式:X?+、X*+、X++、X{n,}+等,成为完全匹配。它和最大匹配一样,一直匹配所有的字符,直到文本的最后,但它不由原路返回。也就是说,一口匹配,搞不定就算了,到也干脆,偶喜欢。
Use a possessive quantifier for situations where you want to seize all of something without ever backing off; it will outperform the equivalent greedy quantifier in cases where the match is not immediately found.
- 13:35
- 浏览 (2123)
- 评论 (0)
- 分类: Java
- 收藏
2009
-
03
-
05
缩略显示
学习正则表达式最佳的材料
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegularExpression {
public static void main(String[] args) {
// 简单认识正则表达式的概念
// p("abc".matches("..."));
// p("a8729a".replaceAll("//d", "-"));
// Pattern p = Pattern.compile("[a-z]{3}");
// Matcher m = p.matcher("fgh");
// p(m.matches());
// p("aaas".matches("[a-z]{3,}"));
// 初步认识. * + ?
// p("a".matches("."));
// p("aa".matches("aa"));
// p("aaaa".matches("a*"));
// p("aaaa".matches("a+"));
// p("".matches("a*"));
// p("aaaa".matches("a?"));
// p("".matches("a?"));
// p("a".matches("a?"));
// p("214523145234532".matches("//d{3,100}"));
// p("192.168.0.231".matches("//d{1,3}//.//d{1,3}//.//d{1,3}//.//d{1,3}"));
// p("192".matches("[0-2][0-9][0-9]"));
// 范围
// p("a".matches("[abc]"));
// p("a".matches("[^abc]"));
// p("A".matches("[a-zA-Z]"));
// p("a".matches("[a-z]|[A-Z]"));
// p("A".matches("[a-z[A-Z]]"));
// p("R".matches("[A-Z&&[RFG]]"));
// 认识/s /w /d /
// p(" /n/r/t".matches("//s{4}"));
// p(" ".matches("//S"));
// p("a_8".matches("//w{3}"));
// p("abc888&^%".matches("[a-z]{1,3}//d+[&^#%]+"));
// p("//".matches("////"));
// POSIX Style
// p("a".matches("//p{Lower}"));
// boundary
// p("hello sir".matches("^h.*"));
// p("hello sir".matches(".*ir$"));
// p("hello sir".matches("^h[a-z]{1,3}o//b.*"));
// p("hellosir".matches("^h[a-z]{1,3}o//b.*")); // whilte lines
// p("/n".matches("^[//s&&[^//n
// p("aaa 8888c".matches(".*//d{4}."));
// p("aaa8888c".matches(".*//b//d{4}."));
// p("aaa8888c".matches(".*//d{4}."));
// p("aaa 8888c".matches(".*//b//d{4}."));
// email
// p("[email protected]".matches("[//w[.-]]+@[//w[.-]]+//.[//w]+"));
// matches find lookingAt
// Pattern p = Pattern.compile("//d{3,5}");
// String s = "123-34345-234-00";
// Matcher m = p.matcher(s);
// p(m.matches());
// m.reset();
// p(m.find());
// p(m.start() + "-" + m.end());
// p(m.find());
// p(m.start() + "-" + m.end());
// p(m.find());
// p(m.start() + "-" + m.end());
// p(m.find());
// //p(m.start() + "-" + m.end());
// p(m.lookingAt());
// p(m.lookingAt());
// p(m.lookingAt());
// p(m.lookingAt());
// replacement
// Pattern p = Pattern.compile("java", Pattern.CASE_INSENSITIVE);
// Matcher m = p
// .matcher("java Java JAVa JaVa IloveJAVA you hateJava afasdfasdf");
// StringBuffer buf = new StringBuffer();
// int i = 0;
// while (m.find()) {
// i++;
// if (i % 2 == 0) {
// m.appendReplacement(buf, "java");
// } else {
// m.appendReplacement(buf, "JAVA");
// }
// }
// m.appendTail(buf);
// p(buf);
// group
// Pattern p = Pattern.compile("(//d{3,5})([a-z]{2})");
// String s = "123aa-34345bb-234cc-00";
// Matcher m = p.matcher(s);
// while (m.find()) {
// p(m.group());
// }
// qulifiers
// Pattern p = Pattern.compile(".{3,10}+[0-9]");
// String s = "aaaa5bbbb68";
// Matcher m = p.matcher(s);
// if (m.find())
// p(m.start() + "-" + m.end());
// else
// p("not match!");
// non-capturing groups
// Pattern p = Pattern.compile(".{3}(?=a)");
// String s = "444a66b";
// Matcher m = p.matcher(s);
// while (m.find()) {
// p(m.group());
// }
// back refenrences
// Pattern p = Pattern.compile("(//d(//d))//2");
// String s = "122";
// Matcher m = p.matcher(s);
// p(m.matches());
// flags的简写
Pattern p = Pattern.compile("java", Pattern.CASE_INSENSITIVE);
p("Java".matches("(?i)(java)"));
}
public static void p(Object o) {
System.out.println(o);
}
}
- 14:05
- 浏览 (630)
- 评论 (1)
- 分类: Java
- 收藏
2009
-
02
-
06
缩略显示
Java snippets02
[java] view plain copy print ?
- if (Character.isLowerCase(ch[i])) {
- char temp = Character.toUpperCase(ch[i]);
- ch[i] = temp;
- } else if (Character.isUpperCase(ch[i])) {
- char temp = Character.toLowerCase(ch[i]);
- ch[i] = temp;
- }
if (Character.isLowerCase(ch[i])) {
char temp = Character.toUpperCase(ch[i]);
ch[i] = temp;
} else if (Character.isUpperCase(ch[i])) {
char temp = Character.toLowerCase(ch[i]);
ch[i] = temp;
}
[java] view plain copy print ?
- while (true) {
- flag = 0;
- result = tc.getNum();
- >
- input = Integer.parseInt(br.readLine());
- >
- while (flag == 0) {
- if (input == result) {
- System.out.println("very good!");
- flag = 1;
- } else {
- flag = 0;
- System.out.println("no,please try again.");
- input = Integer.parseInt(br.readLine());
- }
- }
- }
while (true) {
flag = 0;
result = tc.getNum();
input = Integer.parseInt(br.readLine());
while (flag == 0) {
if (input == result) {
System.out.println("very good!");
flag = 1;
} else {
flag = 0;
System.out.println("no,please try again.");
input = Integer.parseInt(br.readLine());
}
}
}
[java] view plain copy print ?
- L1: while (true) {
- int question = new Times().question();
- L2: while (true) {
- int answer = scanner.nextInt();
- if (answer == question) {
- System.out.println("very good!");
- continue L1;
- } else {
- System.out.println("no,please try again.");
- continue L2;
- }
- }
- }
L1: while (true) {
int question = new Times().question();
L2: while (true) {
int answer = scanner.nextInt();
if (answer == question) {
System.out.println("very good!");
continue L1;
} else {
System.out.println("no,please try again.");
continue L2;
}
}
}
[java] view plain copy print ?
- char[] c1 = s1.toCharArray();
char[] c1 = s1.toCharArray();
[java] view plain copy print ?
- Map m =new HashMap();
- m.put(1, "one");
- m.put(2, "two");
- m.put(3, "three");
- Object o[] = m.values().toArray();
Map m = new HashMap();
m.put(1, "one");
m.put(2, "two");
m.put(3, "three");
Object o[] = m.values().toArray();
[java] view plain copy print ?
- GregorianCalendar ca = new GregorianCalendar();
- System.out.println(ca.get(GregorianCalendar.AM_PM));
GregorianCalendar ca = new GregorianCalendar();
System.out.println(ca.get(GregorianCalendar.AM_PM));
- 14:43
- 浏览 (360)
- 评论 (0)
- 分类: Java
- 收藏
2009
-
02
-
06
缩略显示
Java snippets01
[java] view plain copy print ?
- for (int i =0; i < number.length; i++) {
- for (int j = 0; j < number.length - i - 1; j++) {
- if (number[j] < number[j + 1]) {
- int temp = number[j];
- number[j] = number[j + 1];
- number[j + 1] = temp;
- }
- }
- }
for (int i = 0; i < number.length; i++) {
for (int j = 0; j < number.length - i - 1; j++) {
if (number[j] < number[j + 1]) {
int temp = number[j];
number[j] = number[j + 1];
number[j + 1] = temp;
}
}
}
[java] view plain copy print ?
- BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
- String str = buffer.readLine();
BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
String str = buffer.readLine();
[java] view plain copy print ?
- Scanner scanner = new Scanner(System.in);
- String line = scanner.nextLine();
Scanner scanner = new Scanner(System.in);
String line = scanner.nextLine();
[java] view plain copy print ?
- InputStreamReader in = null;
- OutputStreamWriter out = null;
- BufferedReader br = null;
- in = new InputStreamReader(new FileInputStream(System
- .getProperty("user.dir")
- + "//old.txt"), "UTF-8");
- br = new BufferedReader(in);
- out = new OutputStreamWriter(new FileOutputStream(
- "C://WINDOWS//new.txt"), "UTF-8");
InputStreamReader in = null;
OutputStreamWriter out = null;
BufferedReader br = null;
in = new InputStreamReader(new FileInputStream(System
.getProperty("user.dir")
+ "//old.txt"), "UTF-8");
br = new BufferedReader(in);
out = new OutputStreamWriter(new FileOutputStream(
"C://WINDOWS//new.txt"), "UTF-8");
[java] view plain copy print ?
- String[] temp;
- temp = text.split("//s{1,}");// 按照空格分割字符串,多个空格作为一个空格对字符串进行分割
String[] temp;
temp = text.split("//s{1,}");// 按照空格分割字符串,多个空格作为一个空格对字符串进行分割
[java] view plain copy print ?
- String s = String.valueOf(1);
- if (s.charAt(i) == '1'){}
String s = String.valueOf(1);
if (s.charAt(i) == '1'){}
[java] view plain copy print ?
- System.nanoTime();
System.nanoTime();
[java] view plain copy print ?
- SimpleDateFormat sdt = new SimpleDateFormat("yyyy-MM-DD HH:mm:ss");
- String date = sdt.format(System.currentTimeMillis());
SimpleDateFormat sdt = new SimpleDateFormat("yyyy-MM-DD HH:mm:ss");
String date = sdt.format(System.currentTimeMillis());
[java] view plain copy print ?
- DecimalFormat df = (DecimalFormat) NumberFormat.getInstance();
- df.applyPattern("00");
DecimalFormat df = (DecimalFormat) NumberFormat.getInstance();
df.applyPattern("00");
[java] view plain copy print ?
- Calendar current_time = new GregorianCalendar();
- Calendar target_time = new GregorianCalendar(2009, Calendar.MAY,1);
- long diffMillis = target_time.getTimeInMillis()
- - current_time.getTimeInMillis();
- long diffDays = diffMillis / (24 *60 * 60 * 1000) + 1;
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-DD");
- System.out.println("距" + sdf.format(target_time.getTimeInMillis())
- + "还有:" + diffDays + "天");
Calendar current_time = new GregorianCalendar();
Calendar target_time = new GregorianCalendar(2009, Calendar.MAY, 1);
long diffMillis = target_time.getTimeInMillis()
- current_time.getTimeInMillis();
long diffDays = diffMillis / (24 * 60 * 60 * 1000) + 1;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-DD");
System.out.println("距" + sdf.format(target_time.getTimeInMillis())
+ "还有:" + diffDays + "天");
[java] view plain copy print ?
- Arrays.sort(array);
Arrays.sort(array);
[java] view plain copy print ?
- StringBuilder s1 = new StringBuilder(temp);
-
- System.out.println(s1.reverse());
StringBuilder s1 = new StringBuilder(temp);
// StringBuffer s1 = new StringBuffer(temp);
System.out.println(s1.reverse());
- 13:28
- 浏览 (395)
- 评论 (0)
- 分类: Java
- 收藏
2009
-
02
-
06
缩略显示
双色球算号器
我是个彩民,特别喜欢买双色球。最近看了几种算法,写了一个很简单的双色球的算号器,分享给大家,仅供娱乐,呵呵
[java] view plain copy print ?
- package com.tester.luckly;
- import java.util.Random;
- import java.util.Scanner;
- import java.util.Set;
- import java.util.TreeSet;
- public class DoubleBall {
- private Set hs;
- private static boolean flag = true;
- public enum oddOrEven {
- Odd, Even
- }
- public enum aOrBOrC {
- A, B, C
- }
- public static void main(String[] args) {
- DoubleBall db = new DoubleBall();
- System.out
- .println("====================Red Balls============================");
- String url1 = "http://map.zhcw.com/ssq//html/h7fenqu_ascstr=20.html";
- System.out.println();
- System.err.println(url1);
- Scanner scanner1 = new Scanner(System.in);
- System.out.println("Please select:1.Input your own two numbers");
- System.out
- .println(" 2.Input the range of the two numbers");
- int select = scanner1.nextInt();
- if (select == 1) {
- flag = false;
- } else {
- flag = true;
- }
- System.out.println("Please input two numbers like this: 1 2");
- scanner1.nextLine();
- String[] str = scanner1.nextLine().split(" ");
- Set redBall = db.calcRedBall(Integer.parseInt(str[0]), Integer
- .parseInt(str[1]));
- System.out
- .println("====================Blue Ball============================");
- String url2 = "http://sports.sohu.com/s2007/0445/s252476794/";
- System.out.println();
- System.err.println(url2);
- Scanner scanner2 = new Scanner(System.in);
- System.out.println("1.Please select:" + oddOrEven.Odd +" or "
- + oddOrEven.Even);
- String select1 = scanner2.nextLine();
- System.out.println("2.Please select:" + aOrBOrC.A +" or " + aOrBOrC.B
- + " or " + aOrBOrC.C);
- String select2 = scanner2.nextLine();
- int blueBall = db.calcBlueBall(select1, select2);
- System.out
- .println("====================The Result============================");
- System.out.println();
- for (int i : redBall) {
- System.err.print(i + " ");
- }
- System.err.println("| " + blueBall);
- String url3 = "http://www.bwlc.net/dhtz/";
- System.err.println(url3);
- }
- public Set calcRedBall(int begin,int end) {
- hs = new TreeSet();
-
- hs.add(10);
- hs.add(27);
-
-
- int[] array = { 5, 15, 20, 25, 30, 01, 06, 11, 16, 21, 26, 31 };
- for (int i = 0; i < 2; i++) {
- Random random = new Random();
- hs.add(array[random.nextInt(array.length)]);
- }
-
- if (flag == true) {
- hs.add(begin);
- hs.add(end);
- } else {
- Random random = new Random();
- hs.add(begin + random.nextInt(end - begin + 1));
- }
- while (hs.size() < 6) {
- Random random = new Random();
- hs.add(1 + random.nextInt(33));
- }
- return hs;
- }
- public int calcBlueBall(String select1, String select2) {
- int begin = 1;
- int end = 16;
- if (select2.equals(aOrBOrC.A.toString())) {
- begin = 1;
- end = 5;
- } else if (select2.equals(aOrBOrC.B.toString())) {
- begin = 6;
- end = 10;
- } else {
- begin = 11;
- end = 16;
- }
- Random random = new Random();
- int blueBall = begin + random.nextInt(end - begin +1);
- if (select1.equals(oddOrEven.Odd.toString())) {
- while (blueBall % 2 == 0) {
- blueBall = begin + random.nextInt(end - begin + 1);
- }
- } else {
- while (blueBall % 2 == 1) {
- blueBall = begin + random.nextInt(end - begin + 1);
- }
- }
- return blueBall;
- }
- }
package com.tester.luckly;
import java.util.Random;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeSet;
public class DoubleBall {
private Set hs;
private static boolean flag = true;
public enum oddOrEven {
Odd, Even
}
public enum aOrBOrC {
A, B, C
}
public static void main(String[] args) {
DoubleBall db = new DoubleBall();
System.out
.println("====================Red Balls============================");
String url1 = "http://map.zhcw.com/ssq//html/h7fenqu_ascstr=20.html";
System.out.println();
System.err.println(url1);
Scanner scanner1 = new Scanner(System.in);
System.out.println("Please select:1.Input your own two numbers");
System.out
.println(" 2.Input the range of the two numbers");
int select = scanner1.nextInt();
if (select == 1) {
flag = false;
} else {
flag = true;
}
System.out.println("Please input two numbers like this: 1 2");
scanner1.nextLine();
String[] str = scanner1.nextLine().split(" ");
Set redBall = db.calcRedBall(Integer.parseInt(str[0]), Integer
.parseInt(str[1]));
System.out
.println("====================Blue Ball============================");
String url2 = "http://sports.sohu.com/s2007/0445/s252476794/";
System.out.println();
System.err.println(url2);
Scanner scanner2 = new Scanner(System.in);
System.out.println("1.Please select:" + oddOrEven.Odd + " or "
+ oddOrEven.Even);
String select1 = scanner2.nextLine();
System.out.println("2.Please select:" + aOrBOrC.A + " or " + aOrBOrC.B
+ " or " + aOrBOrC.C);
String select2 = scanner2.nextLine();
int blueBall = db.calcBlueBall(select1, select2);
System.out
.println("====================The Result============================");
System.out.println();
for (int i : redBall) {
System.err.print(i + " ");
}
System.err.println("| " + blueBall);
String url3 = "http://www.bwlc.net/dhtz/";
System.err.println(url3);
}
public Set calcRedBall(int begin, int end) {
hs = new TreeSet();
/*
* 固定恒码:就是每期都必备的号码,通常为2-3个,如02,13,27。 这2-3个号码长期备选(至少50期)。
*/
hs.add(10);
hs.add(27);
/*
* 边缘捡“胆”:就是在边缘码“05、10、15、20、25、30”及“01、
* 06、11、16、21、26、31”共13个号码中巧妙地捡出胆码。之所以 把边缘码作为“胆”码的一种选取方法,是因为从历史中奖号码来看,
* 几乎每一期都会在具备这种特性的号码中出现2-3个。
*/
int[] array = { 5, 15, 20, 25, 30, 01, 06, 11, 16, 21, 26, 31 };
for (int i = 0; i < 2; i++) {
Random random = new Random();
hs.add(array[random.nextInt(array.length)]);
}
/*
* 重码追邻:在上上期出号的左右选取的上期号码,这话不好理解,现举例说明:双色球2007109期开01 04 07 08 13 14;
* 110期开02 04 07 15 24 28;其中这期的04
* 07,刚好是109期二、三位的重码,那么111期的重码该选取哪个呢?重码追邻就是在110期的04 07 的左右选取,110期04 07
* 的左右是02 15。所以111期的备选号就是02 15 了。实际上111期重码刚好开的是02。重码追邻一般选取2-3个号码。
*/
/* ========= 或者========= */
/* 旺区落“胆”。就是在最近几期热号区选择胆码。比如,如果最近的5期内,在中区12~22出号比较密集,那么就要在这个区域里选取3个胆码。这样选择的理由是热码恒热原理,即号码总是在某个区域相对集中出现。 */
if (flag == true) {
hs.add(begin);
hs.add(end);
} else {
Random random = new Random();
hs.add(begin + random.nextInt(end - begin + 1));
}
/* Luck number! */
while (hs.size() < 6) {
Random random = new Random();
hs.add(1 + random.nextInt(33));
}
return hs;
}
public int calcBlueBall(String select1, String select2) {
int begin = 1;
int end = 16;
if (select2.equals(aOrBOrC.A.toString())) {
begin = 1;
end = 5;
} else if (select2.equals(aOrBOrC.B.toString())) {
begin = 6;
end = 10;
} else {
begin = 11;
end = 16;
}
Random random = new Random();
int blueBall = begin + random.nextInt(end - begin + 1);
if (select1.equals(oddOrEven.Odd.toString())) {
while (blueBall % 2 == 0) {
blueBall = begin + random.nextInt(end - begin + 1);
}
} else {
while (blueBall % 2 == 1) {
blueBall = begin + random.nextInt(end - begin + 1);
}
}
return blueBall;
}
}
- 12:29
- 浏览 (2864)
- 论坛浏览 (4047)
- 评论 (7)
- 分类: Java
- 收藏
2009
-
02
-
05
缩略显示
关于用Java I/O 复制文件的问题
今天遇到了一个极其郁闷的问题,想写一段代码,可以给windows自动安装一种字体。
原理就是将4个ttf字体文件复制到C://WINDOWS//Fonts//目录下。本来以为很简单,但用java I/O复制过去的字体不能使用(将记事本的字体改成DejaVuSansMono,如果有效果变化,就是正常的),直接手动复制同样的文件过去,就可以使用。不知道问题出在哪里?
哪位朋友帮忙看看,万分感谢,字体文件在附件中,代码如下:
[java] view plain copy print ?
- package com.test;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.nio.channels.FileChannel;
- public class FontInstall {
- public staticvoid main(String[] args) {
- try {
- String[] fonts = { "DejaVuSansMono-Oblique.ttf",
- "DejaVuSansMono-BoldOblique.ttf", "DejaVuSansMono.ttf",
- "DejaVuSansMono-Bold.ttf" };
- System.out.println();
- for (int i =0; i < fonts.length; i++) {
- FileChannel srcChannel = new FileInputStream(System
- .getProperty("user.dir")
- + "//" + fonts[i]).getChannel();
-
- FileChannel dstChannel = new FileOutputStream(
- "C://WINDOWS//Fonts//" + fonts[i]).getChannel();
- dstChannel.transferFrom(srcChannel, 0, srcChannel.size());
- srcChannel.close();
- dstChannel.close();
- }
- } catch (IOException e) {
- }
- }
- }
package com.test;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
public class FontInstall {
public static void main(String[] args) {
try {
String[] fonts = { "DejaVuSansMono-Oblique.ttf",
"DejaVuSansMono-BoldOblique.ttf", "DejaVuSansMono.ttf",
"DejaVuSansMono-Bold.ttf" };
System.out.println();
for (int i = 0; i < fonts.length; i++) {
// Create channel on the source
FileChannel srcChannel = new FileInputStream(System
.getProperty("user.dir")
+ "//" + fonts[i]).getChannel();
// Create channel on the destination
FileChannel dstChannel = new FileOutputStream(
"C://WINDOWS//Fonts//" + fonts[i]).getChannel();
// Copy file contents from source to destination
dstChannel.transferFrom(srcChannel, 0, srcChannel.size());
// Close the channels
srcChannel.close();
dstChannel.close();
}
} catch (IOException e) {
}
}
}
用另一种写法试了下,也是不行,复制过去的文件大小是相同的,用比较工具比较也没问题。
[java] view plain copy print ?
- package com.test;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- public class FontInstall2 {
- public staticvoid main(String[] args) {
- try {
- String[] fonts = { "DejaVuSansMono-Oblique.ttf",
- "DejaVuSansMono-BoldOblique.ttf", "DejaVuSansMono.ttf",
- "DejaVuSansMono-Bold.ttf" };
- System.out.println();
- for (int i =0; i < fonts.length; i++) {
- InputStream in = new FileInputStream(System
- .getProperty("user.dir")
- + "//" + fonts[i]);
- OutputStream out = new FileOutputStream("C://WINDOWS//Fonts//"
- + fonts[i]);
- byte[] buf = newbyte[1024];
- int len;
- while ((len = in.read(buf)) > 0) {
- out.write(buf, 0, len);
- }
- in.close();
- out.close();
- }
- } catch (IOException e) {
- }
- }
- }
package com.test;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class FontInstall2 {
public static void main(String[] args) {
try {
String[] fonts = { "DejaVuSansMono-Oblique.ttf",
"DejaVuSansMono-BoldOblique.ttf", "DejaVuSansMono.ttf",
"DejaVuSansMono-Bold.ttf" };
System.out.println();
for (int i = 0; i < fonts.length; i++) {
InputStream in = new FileInputStream(System
.getProperty("user.dir")
+ "//" + fonts[i]);
OutputStream out = new FileOutputStream("C://WINDOWS//Fonts//"
+ fonts[i]);
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
}
} catch (IOException e) {
}
}
}
- 新字体.zip (600.1 KB)
- 下载次数: 10
- 17:12
- 浏览 (907)
- 论坛浏览 (739)
- 评论 (5)
- 分类: Java
- 收藏
2009
-
02
-
02
缩略显示
Java util之常用数据类型特性盘点
java.util就相当于c++的STL,是Java的一个非常重要的包,有很多常用的数据类型,不同数据类型有不同的用途,而有些数据类似乎很相似,怎样选择应用,就需要对它们进行辨析。
下面列出了这些数据类型的特点,根据这些特点,就可以有针对性的选用
* 蓝色为接口,绿色为具体实现类
* 缩进的层次结构,就是implement或extend的层次关系
* 每个接口或类都具备其所有上层接口、类的特性
Collection
........|--------List
........|..........|----------ArrayList
........|..........|----------Vector
........|..........|.............|-----Stack
........|..........|----------LinkedList
........|--------Set
...................|----------HashSet.
...................|.............|-----LinkedHashSet
...................|----------SortedSet
.................................|-----TreeSet
Iterator
.....|-------ListIterator
Map
.....|------Hashtable
.....|..........|------Properties
.....|------Hash
Map
.....|..........|------LinkedHash
Map
.....|------WeakHash
Map
.....|------Sorted
Map
................|------Tree
Map
Collection.
●..实现该接口及其子接口的所有类都可应用clone()方法,并是序列化类.
.....List.
.....●..可随机访问包含的元素
.....●..元素是有序的
.....●..可在任意位置增、删元素
.....●..不管访问多少次,元素位置不变
.....●..允许重复元素
.....●..用Iterator实现单向遍历,也可用ListIterator实现双向遍历
..........ArrayList
..........●..用数组作为根本的数据结构来实现List
..........●..元素顺序存储
..........●..新增元素改变List大小时,内部会新建一个数组,在将添加元素前将所有数据拷贝到新数组中
..........●..随机访问很快,删除非头尾元素慢,新增元素慢而且费资源
..........●..较适用于无频繁增删的情况
..........●..比数组效率低,如果不是需要可变数组,可考虑使用数组
..........●..非线程安全
.
..........Vector.
..........●..另一种ArrayList,具备ArrayList的特性
..........●..所有方法都是线程安全的(双刃剑,和ArrayList的主要区别)
..........●..比ArrayList效率低
...............Stack
...............●..LIFO的数据结构
..........LinkedList.
..........●..链接对象数据结构(类似链表)
..........●..随机访问很慢,增删操作很快,不耗费多余资源
..........●..非线程安全
.....Set.
.....●..不允许重复元素,可以有一个空元素
.....●..不可随机访问包含的元素
.....●..只能用Iterator实现单向遍历
..........HashSet
..........●..用Hash
Map作为根本数据结构来实现Set
..........●..元素是无序的
..........●..迭代访问元素的顺序和加入的顺序不同
..........●..多次迭代访问,元素的顺序可能不同
..........●..非线程安全
...............LinkedHashSet
...............●..基于Hash
Map和链表的Set实现
...............●..迭代访问元素的顺序和加入的顺序相同
...............●..多次迭代访问,元素的顺序不便
...............●..因此可说这是一种有序的数据结构
...............●..性能比HashSet差
...............●..非线程安全
..........SortedSet
..........●..加入SortedSet的所有元素必须实现Comparable接口
..........●..元素是有序的
...............TreeSet.
...............●..基于Tree
Map实现的SortedSet
...............●..排序后按升序排列元素
...............●..非线程安全
-----------------------------------
Iterator..
●..对Set、List进行单向遍历的迭代器
..........ListIterator.
..........●..对List进行双向遍历的迭代器
-----------------------------------
Map
●..键值对,键和值一一对应
●..不允许重复的键.
.....Hashtable.
.....●..用作键的对象必须实现了hashcode()、equals()方法,也就是说只有Object及其子类可用作键
.....●..键、值都不能是空对象
.....●..多次访问,映射元素的顺序相同
.....●..线程安全的
..........Properties
..........●..键和值都是字符串
.....Hash
Map
.....●..键和值都可以是空对象
.....●..不保证映射的顺序
.....●..多次访问,映射元素的顺序可能不同
.....●..非线程安全
...............LinkedHash
Map
...............●..多次访问,映射元素的顺序是相同的
...............●..性能比Hash
Map差
.....WeakHash
Map..
.....●..当某个键不再正常使用时,垃圾收集器会移除它,即便有映射关系存在
.....●..非线程安全
.....Sorted
Map.
.....●..键按升序排列
.....●..所有键都必须实现.Comparable.接口.
...............Tree
Map.
...............●..基于红黑树的Sorted
Map实现
...............●..非线程安全
- 12:43
- 浏览 (315)
- 评论 (1)
- 分类: Java
- 收藏
2009
-
02
-
02
缩略显示
一些常用的正则表达式
正则表达式是一种通用的标准,大部分计算机语言都支持正则表达式,包括as3,这里转摘出了一些常用的正则表达式语句,大家用到的时候就不用自己写了
^/d+$ //匹配非负整数(正整数 + 0)
^[0-9]*[1-9][0-9]*$ //匹配正整数
^((-/d+)|(0+))$ //匹配非正整数(负整数 + 0)
^-[0-9]*[1-9][0-9]*$ //匹配负整数
^-?/d+$ //匹配整数
^/d+(/./d+)?$ //匹配非负浮点数(正浮点数 + 0)
^(([0-9]+/.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*/.[0-9]+)|([0-9]*[1-9][0-9]*))$ //匹配正浮点数
^((-/d+(/./d+)?)|(0+(/.0+)?))$ //匹配非正浮点数(负浮点数 + 0)
^(-(([0-9]+/.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*/.[0-9]+)|([0-9]*[1-9][0-9]*)))$ //匹配负浮点数
^(-?/d+)(/./d+)?$ //匹配浮点数
^[A-Za-z]+$ //匹配由26个英文字母组成的字符串
^[A-Z]+$ //匹配由26个英文字母的大写组成的字符串
^[a-z]+$ //匹配由26个英文字母的小写组成的字符串
^[A-Za-z0-9]+$ //匹配由数字和26个英文字母组成的字符串
^/w+$ //匹配由数字、26个英文字母或者下划线组成的字符串
^[/w-]+(/.[/w-]+)*@[/w-]+(/.[/w-]+)+$ //匹配email地址
^[a-zA-z]+://匹配(/w+(-/w+)*)(/.(/w+(-/w+)*))*(/?/S*)?$ //匹配url
匹配中文字符的正则表达式: [/u4e00-/u9fa5]
匹配双字节字符(包括汉字在内):[^/x00-/xff]
匹配空行的正则表达式:/n[/s| ]*/r
匹配HTML标记的正则表达式:/<(.*)>.*/>|<(.*) //>/
匹配首尾空格的正则表达式:(^/s*)|(/s*$)
匹配Email地址的正则表达式:/w+([-+.]/w+)*@/w+([-.]/w+)*/./w+([-.]/w+)*
匹配网址URL的正则表达式:^[a-zA-z]+://(/w+(-/w+)*)(/.(/w+(-/w+)*))*(/?/S*)?$
匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
匹配国内电话号码:(/d{3}-|/d{4}-)?(/d{8}|/d{7})?
匹配腾讯QQ号:^[1-9]*[1-9][0-9]*$
下表是元字符及其在正则表达式上下文中的行为的一个完整列表:
/ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个后向引用、或一个八进制转义符。
^ 匹配输入字符串的开始位置。如果设置了 RegExp 对象的Multiline 属性,^ 也匹配 ’/n’ 或 ’/r’ 之后的位置。
$ 匹配输入字符串的结束位置。如果设置了 RegExp 对象的Multiline 属性,$ 也匹配 ’/n’ 或 ’/r’ 之前的位置。
* 匹配前面的子表达式零次或多次。
+ 匹配前面的子表达式一次或多次。+ 等价于 {1,}。
? 匹配前面的子表达式零次或一次。? 等价于 {0,1}。
{n} n 是一个非负整数,匹配确定的n 次。
{n,} n 是一个非负整数,至少匹配n 次。
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。在逗号和两个数之间不能有空格。
? 当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。
. 匹配除 "/n" 之外的任何单个字符。要匹配包括 ’/n’ 在内的任何字符,请使用象 ’[./n]’ 的模式。
(pattern) 匹配pattern 并获取这一匹配。
(?:pattern) 匹配pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。
(?=pattern) 正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。
(?!pattern) 负向预查,与(?=pattern)作用相反
x|y 匹配 x 或 y。
[xyz] 字符集合。
[^xyz] 负值字符集合。
[a-z] 字符范围,匹配指定范围内的任意字符。
[^a-z] 负值字符范围,匹配任何不在指定范围内的任意字符。
/b 匹配一个单词边界,也就是指单词和空格间的位置。
/B 匹配非单词边界。
/cx 匹配由x指明的控制字符。
/d 匹配一个数字字符。等价于 [0-9]。
/D 匹配一个非数字字符。等价于 [^0-9]。
/f 匹配一个换页符。等价于 /x0c 和 /cL。
/n 匹配一个换行符。等价于 /x0a 和 /cJ。
/r 匹配一个回车符。等价于 /x0d 和 /cM。
/s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于[ /f/n/r/t/v]。
/S 匹配任何非空白字符。等价于 [^ /f/n/r/t/v]。
/t 匹配一个制表符。等价于 /x09 和 /cI。
/v 匹配一个垂直制表符。等价于 /x0b 和 /cK。
/w 匹配包括下划线的任何单词字符。等价于’[A-Za-z0-9_]’。
/W 匹配任何非单词字符。等价于 ’[^A-Za-z0-9_]’。
/xn 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。
/num 匹配 num,其中num是一个正整数。对所获取的匹配的引用。
/n 标识一个八进制转义值或一个后向引用。如果 /n 之前至少 n 个获取的子表达式,则 n 为后向引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。
/nm 标识一个八进制转义值或一个后向引用。如果 /nm 之前至少有is preceded by at least nm 个获取得子表达式,则 nm 为后向引用。如果 /nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的后向引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则 /nm 将匹配八进制转义值 nm。
/nml 如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八
- 12:34
- 浏览 (268)
- 评论 (0)
- 分类: Java
- 收藏
2009
-
01
-
21
缩略显示
编程经典问题
【程序1】
题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?
1.程序分析: 兔子的规律为数列1,1,2,3,5,8,13,21....
【程序2】
题目:判断101-200之间有多少个素数,并输出所有素数。
1.程序分析:判断素数的方法:用一个数分别去除2到sqrt(这个数),如果能被整除,
则表明此数不是素数,反之是素数。
【程序3】
题目:打印出所有的"水仙花数",所谓"水仙花数"是指一个三位数,其各位数字立方和等于该数本身。例如:153是一个"水仙花数",因为153=1的三次方+5的三次方+3的三次方。
1.程序分析:利用for循环控制100-999个数,每个数分解出个位,十位,百位。
【程序4】
题目:将一个正整数分解质因数。例如:输入90,打印出90=2*3*3*5。
程序分析:对n进行分解质因数,应先找到一个最小的质数k,然后按下述步骤完成:
(1)如果这个质数恰等于n,则说明分解质因数的过程已经结束,打印出即可。
(2)如果n<>k,但n能被k整除,则应打印出k的值,并用n除以k的商,作为新的正整数你n,重复执行第一步。
(3)如果n不能被k整除,则用k+1作为k的值,重复执行第一步。
【程序5】
题目:利用条件运算符的嵌套来完成此题:学习成绩>=90分的同学用A表示,60-89分之间的用B表示,60分以下的用C表示。
1.程序分析:(a>b)?a:b这是条件运算符的基本例子。
【程序6】
题目:输入两个正整数m和n,求其最大公约数和最小公倍数。
1.程序分析:利用辗除法。
【程序7】
题目:输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数。
1.程序分析:利用while语句,条件为输入的字符不为'/n'.
【程序8】
题目:求s=a+aa+aaa+aaaa+aa...a的值,其中a是一个数字。例如2+22+222+2222+22222(此时共有5个数相加),几个数相加有键盘控制。
1.程序分析:关键是计算出每一项的值。
【程序9】
题目:一个数如果恰好等于它的因子之和,这个数就称为"完数"。例如6=1+2+3.编程 找出1000以内的所有完数。
【程序10】
题目:一球从100米高度自由落下,每次落地后反跳回原高度的一半;再落下,求它在 第10次落地时,共经过多少米?第10次反弹多高?
【程序11】
题目:有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?
1.程序分析:可填在百位、十位、个位的数字都是1、2、3、4。组成所有的排列后再去 掉不满足条件的排列。
【程序12】
题目:企业发放的奖金根据利润提成。利润(I)低于或等于10万元时,奖金可提10%;利润高于10万元,低于20万元时,低于10万元的部分按 10%提成,高于10万元的部分,可可提成7.5%;20万到40万之间时,高于20万元的部分,可提成5%;40万到60万之间时高于40万元的部分,可提成3%;60万到100万之间时,高于60万元的部分,可提成1.5%,高于100万元时,超过100万元的部分按1%提成,从键盘输入当月利润I,求应发放奖金总数?
1.程序分析:请利用数轴来分界,定位。注意定义时需把奖金定义成长整型。
【程序13】
题目:一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少?
1.程序分析:在10万以内判断,先将该数加上100后再开方,再将该数加上268后再开方,如果开方后的结果满足如下条件,即是结果。请看具体分析:
【程序14】
题目:输入某年某月某日,判断这一天是这一年的第几天?
1.程序分析:以3月5日为例,应该先把前两个月的加起来,然后再加上5天即本年的第几天,特殊情况,闰年且输入月份大于3时需考虑多加一天。
【程序15】
题目:输入三个整数x,y,z,请把这三个数由小到大输出。
1.程序分析:我们想办法把最小的数放到x上,先将x与y进行比较,如果x>y则将x与y的值进行交换,然后再用x与z进行比较,如果x>z则将x与z的值进行交换,这样能使x最小。
【程序16】
题目:输出9*9口诀。
1.程序分析:分行与列考虑,共9行9列,i控制行,j控制列。
【程序17】
题目:猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个 第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下 的一半零一个。到第10天早上想再吃时,见只剩下一个桃子了。求第一天共摘了多少。
1.程序分析:采取逆向思维的方法,从后往前推断。
【程序18】
题目:两个乒乓球队进行比赛,各出三人。甲队为a,b,c三人,乙队为x,y,z三人。已抽签决定比赛名单。有人向队员打听比赛的名单。a说他不和x比,c说他不和x,z比,请编程序找出三队赛手的名单。
1.程序分析:判断素数的方法:用一个数分别去除2到sqrt(这个数),如果能被整除, 则表明此数不是素数,反之是素数。
【程序19】
题目:打印出如下图案(菱形)
*
***
******
********
******
***
*
1.程序分析:先把图形分成两部分来看待,前四行一个规律,后三行一个规律,利用双重 for循环,第一层控制行,第二层控制列。
【程序20】
题目:有一分数序列:2/1,3/2,5/3,8/5,13/8,21/13...求出这个数列的前20项之和。
1.程序分析:请抓住分子与分母的变化规律。
【程序21】
题目:求1+2!+3!+...+20!的和
1.程序分析:此程序只是把累加变成了累乘。
【程序22】
题目:利用递归方法求5!。
1.程序分析:递归公式:fn=fn_1*4!
【程序23】
题目:有5个人坐在一起,问第五个人多少岁?他说比第4个人大2岁。问第4个人岁数,他说比第3个人大2岁。问第三个人,又说比第2人大两岁。问第2个人,说比第一个人大两岁。最后问第一个人,他说是10岁。请问第五个人多大?
1.程序分析:利用递归的方法,递归分为回推和递推两个阶段。要想知道第五个人岁数,需知道第四人的岁数,依次类推,推到第一人(10岁),再往回推。
【程序24】
题目:给一个不多于5位的正整数,要求:一、求它是几位数,二、逆序打印出各位数字。
【程序25】
题目:一个5位数,判断它是不是回文数。即12321是回文数,个位与万位相同,十位与千位相同。
【程序26】
题目:请输入星期几的第一个字母来判断一下是星期几,如果第一个字母一样,则继续 判断第二个字母。
1.程序分析:用情况语句比较好,如果第一个字母一样,则判断用情况语句或if语句判断第二个字母。
【程序27】
题目:求100之内的素数
【程序28】
题目:对10个数进行排序
1.程序分析:可以利用选择法,即从后9个比较过程中,选择一个最小的与第一个元素交换, 下次类推,即用第二个元素与后8个进行比较,并进行交换。
【程序29】
题目:求一个3*3矩阵对角线元素之和
1.程序分析:利用双重for循环控制输入二维数组,再将a[i][i]累加后输出。
【程序30】
题目:有一个已经排好序的数组。现输入一个数,要求按原来的规律将它插入数组中。
1. 程序分析:首先判断此数是否大于最后一个数,然后再考虑插入中间的数的情况,插入后此元素之后的数,依次后移一个位置。
【程序31】
题目:将一个数组逆序输出。
1.程序分析:用第一个与最后一个交换。
【程序32】
题目:取一个整数a从右端开始的4~7位。
程序分析:可以这样考虑:
(1)先使a右移4位。
(2)设置一个低4位全为1,其余全为0的数。可用~(~0<<4)
(3)将上面二者进行&运算。
【程序33】
题目:打印出杨辉三角形(要求打印出10行如下图)
1.程序分析:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
【程序34】
题目:输入3个数a,b,c,按大小顺序输出。
1.程序分析:利用指针方法。
【程序35】
题目:输入数组,最大的与第一个元素交换,最小的与最后一个元素交换,输出数组。
【程序36】
题目:有n个整数,使其前面各数顺序向后移m个位置,最后m个数变成最前面的m个数
【程序37】
题目:有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位。
【程序38】
题目:写一个函数,求一个字符串的长度,在main函数中输入字符串,并输出其长度。
【程序39】
题目:编写一个函数,输入n为偶数时,调用函数求1/2+1/4+...+1/n,当输入n为奇数时,调用函数1/1+1/3+...+1/n(利用指针函数)
【程序40】
题目:字符串排序。
【程序41】
题目:海滩上有一堆桃子,五只猴子来分。第一只猴子把这堆桃子凭据分为五份,多了一个,这只猴子把多的一个扔入海中,拿走了一份。第二只猴子把剩下的桃子又平均分成五份,又多了一个,它同样把多的一个扔入海中,拿走了一份,第三、第四、第五只猴子都是这样做的,问海滩上原来最少有多少个桃子?
【程序42】
题目:809*??=800*??+9*??+1 其中??代表的两位数,8*??的结果为两位数,9*??的结果为3位数。求??代表的两位数,及809*??后的结果。
【程序43】
题目:求0—7所能组成的奇数个数。
【程序44】
题目:一个偶数总能表示为两个素数之和。
【程序45】
题目:判断一个素数能被几个9整除
【程序46】
题目:两个字符串连接程序
【程序47】
题目:读取7个数(1—50)的整数值,每读取一个值,程序打印出该值个数的*。
【程序48】
题目:某个公司采用公用电话传递数据,数据是四位的整数,在传递过程中是加密的,加密规则如下:每位数字都加上5,然后用和除以10的余数代替该数字,再将第一位和第四位交换,第二位和第三位交换。
【程序49】
题目:计算字符串中子串出现的次数
【程序50】
题目:有五个学生,每个学生有3门课的成绩,从键盘输入以上数据(包括学生号,姓名,三门课成绩),计算出平均成绩,况原有的数据和计算出的平均分数存放在磁盘文件"stud"中。
- 16:43
- 浏览 (1671)
- 评论 (2)
- 分类: Java
- 收藏
2009
-
01
-
20
缩略显示
Java中格式化输出数字
在实际工作中,常常需要设定数字的输出格式,如以百分比的形式输出,或者设定小数位数等,现稍微总结如下。
主要使用的类:java.text.DecimalFormat
1。实例化对象,可以用如下两种方法:
DecimalFormat df=(DecimalFormat)NumberFormat.getInstance();
DecimalFormat df1=(DecimalFormat) DecimalFormat.getInstance();
因为DecimalFormat继承自NumberFormat。
2。设定小数位数
系统默认小数位数为3,如:
DecimalFormat df=(DecimalFormat)NumberFormat.getInstance();
System.out.println(df.format(12.3456789));
输出:12.346
现在可以通过如下方法把小数为设为两位:
df.setMaximumFractionDigits(2);
System.out.println(df.format(12.3456789));
则输出为:12.35
3。将数字转化为百分比输出,有如下两种方法:
(1)
df.applyPattern("##.##%");
System.out.println(df.format(12.3456789));
System.out.println(df.format(1));
System.out.println(df.format(0.015));
输出分别为:1234.57% 100% 1.5%
(2)
df.setMaximumFractionDigits(2);
System.out.println(df.format(12.3456789*100)+"%");
System.out.println(df.format(1*100)+"%");
System.out.println(df.format(0.015*100)+"%");
输出分别为:
1,234.57% 100% 1.5%
4。设置分组大小
DecimalFormat df1=(DecimalFormat) DecimalFormat.getInstance();
df1.setGroupingSize(2);
System.out.println(df1.format(123456789));
输出:1,23,45,67,89
还可以通过df1.setGroupingUsed(false);来禁用分组设置,如:
DecimalFormat df1=(DecimalFormat) DecimalFormat.getInstance();
df1.setGroupingSize(2);
df1.setGroupingUsed(false);
System.out.println(df1.format(123456789));
输出:123456789
5。设置小数为必须为2位
DecimalFormat df2=(DecimalFormat) DecimalFormat.getInstance();
df2.applyPattern("0.00");
System.out.println(df2.format(1.2));
输出:1.20
java.text.DecimalFormat学习笔记
例子:
import java.text.*;
public class Untitled1 {
public static void main(String[] args) {
//---------------------------------------------
//定义一个数字格式化对象,格式化模板为".##",即保留2位小数.
DecimalFormat a = new DecimalFormat(".##");
String s= a.format(333.335);
System.err.println(s);
//说明:如果小数点后面不够2位小数,不会补零.参见Rounding小节
//---------------------------------------------
//-----------------------------------------------
//可以在运行时刻用函数applyPattern(String)修改格式模板
//保留2位小数,如果小数点后面不够2位小数会补零
a.applyPattern(".00");
s = a.format(333.3);
System.err.println(s);
//------------------------------------------------
//------------------------------------------------
//添加千分号
a.applyPattern(".##/u2030");
s = a.format(0.78934);
System.err.println(s);//添加千位符后,小数会进三位并加上千位符
//------------------------------------------------
//------------------------------------------------
//添加百分号
a.applyPattern("#.##%");
s = a.format(0.78645);
System.err.println(s);
//------------------------------------------------
//------------------------------------------------
//添加前、后修饰字符串,记得要用单引号括起来
a.applyPattern("'这是我的钱$',###.###'美圆'");
s = a.format(33333443.3333);
System.err.println(s);
//------------------------------------------------
//------------------------------------------------
//添加货币表示符号(不同的国家,添加的符号不一样
a.applyPattern("/u00A4");
s = a.format(34);
System.err.println(s);
//------------------------------------------------
//-----------------------------------------------
//定义正负数模板,记得要用分号隔开
a.applyPattern("0.0;'@'-#.0");
s = a.format(33);
System.err.println(s);
s = a.format(-33);
System.err.println(s);
//-----------------------------------------------
//综合运用,正负数的不同前后缀
String pattern="'my moneny'###,###.##'RMB';'ur money'###,###.##'US'";
a.applyPattern(pattern);
System.out.println(a.format(1223233.456));
}
}
总结:
要生成一个DecimalFormat对象,一般只要通过NumberFormat类工厂的getInstance()来取得一个 NumberFormat对象再将其转换成DecimalFormat对象,然后通过DecimalForat对象的applyPattern()来动态改变数据的现示格式模板,通过format()方法取得格式化后的数字。同时,DecimalFormat提供了许多的方法来返回格式化后的数字的某一部份,这些方法如:getNegativeSuffix()。这个类的难点主要是在模板的书写及理解上。其实主要的就是针对一个数字的正负形式来设定不同的格式显示。这里要特别注意的是使用在模板上的特殊字符代表有特殊的意义,如下表所示:
Symbol Description
0 a digit
# a digit, zero shows as absent
. placeholder for decimal separator
, placeholder for grouping separator
E separates mantissa and exponent for exponential formats
; separates formats
- default negative prefix
% multiply by 100 and show as percentage
? multiply by 1000 and show as per mille
¤ currency sign; replaced by currency symbol; if doubled, replaced by international currency symbol; if present in a pattern, the monetary decimal separator is used instead of the decimal separator
X any other characters can be used in the prefix or suffix
' used to quote special characters in a prefix or suffix
例如:如果模板中含有#,意思是指这个#号可代表一个或多个数字如果该位的数字是零的话则省略该位。另:注意“#,##0.0#;(#)”这个模板的意思是指数字的负数形式跟正数的一样。
- 12:15
- 浏览 (1451)
- 评论 (0)
- 分类: Java
- 收藏
2009
-
01
-
08
缩略显示
右键运行jar文件的方法
经常需要运行一些打成jar文件格式的Java程序,每次都需要切换到DOS下运行命令:
java -jar FileName.jar ,非常的麻烦。
其实可以将jar文件的默认打开方式设置成jre中的javaw,设置好后可以双击jar文件运行。但这样的话,需要查看包中内容的时候又非常麻烦,需要将jar文件拖到解压缩工具中。
今天突发奇想,改写了一个批处理文件,可以将java -jar命令加到鼠标右键中:
reg add "HKCR/*/shell/Run_Jar" /ve /d Run_Jar /f
reg add "HKCR/*/shell/Run_Jar/command" /ve /d "java -jar %%1" /f
reg add "HKCR/Folder/shell/Run_Jar" /ve /d Run_Jar /f
reg add "HKCR/Folder/shell/Run_Jar/command" /ve /d "java -jar %%1" /f
将上面的代码保存为bat文件,然后双击执行,执行后,鼠标右键中会出现Run_Jar选项。
这下你就可以在你想运行的jar文件上点击右键,然后Run_Jar,怎么样,比较方便吧:)
稍微解释一下上面的命令:
reg add "HKCR/*/shell/Run_Jar"
在注册表中的
HKEY_CLASSES_ROOT/*shell/ 目录下添加键值,后面参数的意思分别是:
/ve 为注册表项添加空白值名<无名称>
/d 要分配给添加的注册表 ValueName 的数据
/f 不用提示就强行改写现有注册表项
- 12:11
- 浏览 (3231)
- 评论 (2)
- 分类: Java
- 收藏
2009
-
01
-
07
缩略显示
开心网外挂开发手记
开讲。
做一个Web游戏外挂需要的准备知识:
1) 需要有耐心
2) 熟悉HTML, JavaScript,特别是FORM
3) 熟悉HTTP协议,特别是Cookie, URL的编码方式和POST, GET内容格式
4) 熟悉游戏本身,能抽象出最优的赚钱/升级的数学模型
5) 掌握一门语言,白菜萝卜都可以,我比较喜欢用Python和C#
6) 需要一些抓包的工具,比如Fiddler
好了,来个例子,开心网争车位.
首先,我们看看一个正常用户玩的时候是怎么玩的。
1) 浏览器输入 www.kaixin001.com ,输入用户名,密码,点登陆
2) 登陆后选择左侧的“争车位”,进入到争车位
3) 看看谁在我的车位里,一一贴条
4) 看看自己的车哪些停车时间操作15分钟了,一一找个空的不免费的车位挪过去
5) 登出开心网,关闭浏览器
看看让程序怎么来实现1-6。
1) 登陆开心网
在Fiddler的帮助下,我们知道登陆是把FORM提交到/login/login.php,POST内容是url=%
[email protected]&password=xxx
用C#可以方便的完成这个POST操作,然后得到服务器的返回,然后根据返回的内容里找一个关键字就可以判断这次登陆操作是否成功了。(比如我找的就是"
我的首页 - 开心网")
2) 登陆争车位
这次是一个GET操作,URL是/app/app.php?aid=1040。
需要说明一下的是,这里没有提供用户名密码,服务器怎么能知道是哪个用户呢?Cookie在这里就发挥了它的作用。
C#里存放Cookie的方法是new 一个CookieContainer,然后所有的HttpWebRequest的CookieContainer都用它。
好了,取得这个页面以后,我们能得到很多信息:(这些信息是JSON格式)
a) 好友列表,每个好友的状态(在线/车位满)
b) 自己的车库信息,停了那些好友的哪些车,分别赚了多少钱
c) 自己的汽车信息,多少辆车,分别停在哪里,赚了多少钱
根据这些信息,我们可以得到一个停放的列表(车位不满的好友列表)
3) 贴条
贴条是一个POST操作,URL是/parking/post.php,内容是verify=xxx&parkid=yyy&p=1&_=
parkid很好理解,车库信息里直接可以取到,那么verify怎么得到的呢?
我当初的第一反应是Cookie数据通过某种运算得到的,不过后来我看了登陆争车位的html后才发现原来这个verify是这样写的:
...