[Java]Annotation元数据的几个应用||Java使用Annotation实现I18N

Tiger出笼以后, Annotation成了一个小小的亮点,虽然有抄袭.net之嫌疑,毕竟让Java开发者方便了许多。EJB3.0和Hibernate Annotation版都是基于这个东西了。下面是结合Spring的自动Log/鉴权/国际化应用:

public interface SessionService extends Service {
    @Anonymous //允许未登录用户调用
    @OperationLog //自动log
    @Name(zh = “登录”)
    public String login(
            @Name(en=”user”,zh = “用户”)String user,
            @OperationLog(false)String password); //不log密码

    @OperationLog
    @Name(zh=”注销”)
    public void logout();

@Anonymous用于鉴权,允许匿名访问。通过ThreadLocal的变量保存当前用户的Session信息。
@OperationLog 用于标记是否自动Log, 可以作用于类、方法、参数
@Name用于i18n国际化支持。Java里面常见的国际化解决方法是.properties文件,个人认为这个方案不好,适合大型项目开发。小项目中这个标记一下足矣。如果要添加一种语言,只要在@Name中多一个参数,利用Eclipse的reference很容易知道有哪些地方要翻译。

同样@Name还可以加在Bean上,自动构造多语言的Table/List,方便之极。

@Name(zh=”安全事件”,en=”Security Event”)
public class SecurityEvent extends AbstractEmsEvent{
    String cause;
    @Name(zh=”原因”)
    public String getCause() {
        return cause;
    }
    
}

附上我的I18nUtil工具类:

/**
 * @author steeven
 */
public class I18nUtil {
    public static String getName(Method method) {
        return getI18n(method,Name.class);
    }
    public static String getTip(Method method) {
        return getI18n(method,Tip.class);
    }
    public static String getI18n(Method method,Class<? extends Annotation> i18nClass) {
        Annotation i18n = method.getAnnotation(i18nClass);
        return getProperty(i18n,method.getName());
    }

    public static String getProperty(Annotation i18n, String defaultValue) {
        if (i18n==null)
            return defaultValue;
        Class<? extends Annotation> clz = i18n.annotationType();
        try {
            Method method = clz.getMethod(getI18nMethodName());
            assert method!=null;
            String r = (String) method.invoke(i18n);
            return r==null || r.length()==0?defaultValue:r;
        } catch (Exception e) {
            assert false;
            return defaultValue;
        }
    }

    private static String getI18nMethodName() {
        return Locale.getDefault().getLanguage();
    }

    @SuppressWarnings(“unchecked”)
    public static <T extends Annotation> T getAnnotation(Annotation[] argAnnotations, Class<T> clz) {
        for(Annotation anno:argAnnotations)
            if (clz.isInstance(anno))
                return (T) anno;
        return null;
    }
}

元数据的结构似乎有些简单,有时候要加很多@Name,@Tip,@Help好像没办法一个Tag搞定。

另外,还可以通过Annotation加上验证、输入界面描述,等等。程序很容易自动化,再多的画面也用不了多少代码。

Jdk5.0提供了这么好用的原数据机制,你有什么好的用法呢?

From: http://www.cnblogs.com/steeven/archive/2005/07/28/201684.html

Java i18n的简单实现

package com.joshua.code.sample.i18n.bundle;

import java.util.Locale;

import java.util.ResourceBundle;

public class I18NUtils {

private static final String ENGLISH_LANGUAGE = Locale.ENGLISH.getLanguage();

private static ResourceBundle RES_BUNDLE;
public static Locale LOCALE;

static {
Locale defLocale = Locale.getDefault();
if (defLocale.getLanguage().equals(ENGLISH_LANGUAGE)) {
Locale.setDefault(Locale.ENGLISH);
}
RES_BUNDLE = ResourceBundle.getBundle(
“com.joshua.code.sample.i18n.bundle.resources.messages”,
defLocale);
}
}

public static void setLocale(Locale loc) {
LOCALE = loc;
RES_BUNDLE = ResourceBundle.getBundle(
“com.joshua.code.sample.i18n.bundle.resources.messages”, loc);
}

public static String getResValue(String key) {
if (key == null) return null;
String resKey = key.replace(‘ ‘, ‘_’);
resKey = resKey.toLowerCase(java.util.Locale.ENGLISH);
if (RES_BUNDLE.containsKey(resKey)) {
return RES_BUNDLE.getString(resKey);
} else {
return null;
}
}

public static void main(String[] args) {
// I18NUtils.setLocale(Locale.GERMAN);
// I18NUtils.setLocale(Locale.FRENCH);
// I18NUtils.setLocale(Locale.JAPAN);
I18NUtils.setLocale(Locale.CHINA);
// I18NUtils.setLocale(Locale.TAIWAN);
System.out.println(I18NUtils.getResValue(“add”));
}

}

 

 

所有工程相关的文件请从附件下载。

  • JoshuaCodeRepo.zip (5.8 KB)
  • 下载次数: 15
  • From: http://joshuasabrina.iteye.com/blog/1825230

java中 locale类 及相关方法

 Object clone() 
          重写 Cloneable。 
 boolean equals(Object obj) 
          如果该 Locale 等于另一个对象,则返回 true。 
static Locale[] getAvailableLocales() 
          返回所有已安装语言环境的数组。 
 String getCountry() 
          返回此语言环境的国家/地区代码,将为空字符串或大写的 ISO 3166 两字母代码。 
static Locale getDefault() 
          获得此 Java 虚拟机实例的当前默认语言环境值。 
 String getDisplayCountry() 
          返回适合向用户显示的语言环境国家/地区名。 
 String getDisplayCountry(Locale inLocale) 
          返回适合向用户显示的语言环境国家/地区名。 
 String getDisplayLanguage() 
          返回适合向用户显示的语言环境语言名。 
 String getDisplayLanguage(Locale inLocale) 
          返回适合向用户显示的语言环境语言名。 
 String getDisplayName() 
          返回适合向用户显示的语言环境名。 
 String getDisplayName(Locale inLocale) 
          返回适合向用户显示的语言环境名。 
 String getDisplayVariant() 
          返回适合向用户显示的语言环境变量代码名。 
 String getDisplayVariant(Locale inLocale) 
          返回适合向用户显示的语言环境变量代码名。 
 String getISO3Country() 
          返回此语言环境国家/地区的三字母缩写。 
 String getISO3Language() 
          返回此语言环境语言的三字母缩写。 
static String[] getISOCountries() 
          返回 ISO 3166 中所定义的所有两字母国家/地区代码。 
static String[] getISOLanguages() 
          返回 ISO 639 中所定义的所有两字母语言代码。 
 String getLanguage() 
          返回此语言环境的语言代码,可以是空字符串或小写的 ISO 639 代码。 
 String getVariant() 
          返回此语言环境的变量代码。 
 int hashCode() 
          重写 hashCode。 
static void setDefault(Locale newLocale) 
          为此 Java 虚拟机实例设置默认语言环境。 
 String toString() 
          使用由下划线分隔的语言、国家/地区和变量来获取整个语言环境的编程名称。

开除员工,六个理由随便挑一个就够了

看似一篇杂文,不过也有收获,找找自己的问题也好,看看热闹也罢。权当消遣。

本文作者Matthew Bellows,Yesware软件公司创始人。

我一辈子被开除过两次,深知被开后心情是非常不爽的。年轻的时候喜欢闯荡,第一次被开除觉得是对自我的释放,但是渐渐发现,这是对自己的不负责,顺带失业6个月。

现在我自己开了一家公司,要为团队的发展担忧。招聘,算是我最喜欢的一个环节,可以跟许多有能力的人交流,并邀请有识之士进入团队。当然,开除员工也在所难免,当员工与团队或者公司的发展无法保持同步之时,我们就会考虑开除他。

在我的公司,在开除员工之前,我们会从5个品质以及一个关键因素出发对员工进行分析,最后得出是否开除的决定。

这五个品质是开除员工之前首先要考虑的不分,如果员工已经缺少了其中几个或者全部品质,我们会以最可气最尊重的方式将其“请出公司”:

1、高效率:公司不是一个大家庭,而是一个高效率的团队。每个企业都想研发出世界级的产品,这就需要所有员工都能保持高效率。如果员工做不到这一点,照Netflix首席执行官Reed Hastings的话说就是:“赶紧地,打包走人。”

2、积极性:所有进入公司的员工工作之初都是非常积极的,但因为产品研发需要一定的周期,这可能会抹杀许多人的积极性,但是这种积极性需要维持下去或者得到提升。同时也需要勇气。如果我们发现员工没有了积极性,工作不再积极,我们就会考虑换人。当然我们更欣赏那些工作积极,充满热情的员工。

3、成长:对于一个快速发展的企业来说,改变是不可避免的,所以就要求提高适应变化的能力,提高技术水平。在我的企业中,我非常看重员工在经过一段时间的工作之后能不能得到成长,如果没法成长,抱歉!

4、诚实与自律:这两点是做人的基本原则,如果员工连诚实、自律都做不到,除了祸害团队其他成员,我还找不出别的功能。公司尊重员工,员工也应该尊重企业。

5、宽容:在一个快速发展的企业中,员工都处在高压状态下。企业工作多,客户需求也多。即便有压力,我们要对自己宽容,也要对客户宽容。宽容的意义还要更宽,比如不歧视,无性别和种族主义,不侮辱他人等。

所以说,如果有员工出现了不符合以上品质的情况,我们开除他的几率就会变得非常大。但是在任何一家公司,不能说开除就开除,得有一个正式的理由,我个人认为最有用的也是最关键的就是“企业资金预算不够”。

另外对于一家企业来说,开除人也就意味着要继续招聘人,不能让零和游戏出现负数。另外也要在用人过程中严禁出现“员工排序”的情况,因为这种制度已经导致微软等大企业停滞不前。

开除员工,并不是一个轻松的话题,对于员工和企业来说都非常重要。任何加入创业企业的员工都要清楚地认清他们未来几年的工作状况,创业者也要对他们所处的和所打造的环境诚实、负责。在不符合公司发展规划的员工没有打乱这个环境之前,最好还是以相互尊重的方式将其“开除”。

文章来源:Businessinsider

转自:http://tech2ipo.com/56373

如非特别注明,本站内容均为OneCoder原创,转载请务必注明作者和原始出处。
本文地址:http://www.coderli.com/6-reasons-to-fire-someone-matthew-bellows-yesware

解密微软失落十年:消极员工排序 官僚主义盛行

今年8月号的《名利场》(Vanity Fair)杂志刊文,对微软失落的十年进行了深入解读。由于官僚主义盛行,以及制度设计缺陷,导致这家曾经不可一世的软件巨头裹足不前,屡屡错失发展机遇。

解密微软失落十年:消极员工排序 官僚主义盛行

消极制度设计

微软失落的十年可以称得上是美国商业史上最大的谜团。两度获得乔治·波卡奖(George Polk Award)的库特·爱琴沃尔德(Kurt Eichenwald)希望解开这个谜团,为此,他研究了微软“不可思议的愚蠢决策”,最终认为,这完全可以成为商学院的案例,专门用于研究“成功陷阱”。

通过数十次采访以及大量的公司内部文件——包括最高管理者之间的电子邮件往来——爱琴沃尔德史无前例地向外界展现了现任CEO史蒂夫·鲍尔默(Steve Ballmer)领导下的微软的生存状况,并发表在8月号的《名利场》上。今天,苹果仅凭iPhone一款产品,就超过了微软所有业务的收入总和。

爱琴沃尔德揭示了一种名为“员工排序”(stack ranking)的管理系统。在这种系统中,每个部门都要将特定比例的员工归入卓越、优秀、普通和糟糕四大类别,这在很大程度上限制了微软的创新能力。“我采访的每一个微软现任和前任员工都认为,‘员工排序’是微软内部最消极的制度——所有人都这么认为。这已经导致不计其数的员工离职。”爱琴沃尔德写道。

一位微软前软件工程师说:“如果你供职于一个10人团队,却在就职第一天发现,无论大家表现多么优异,总有2个人会得到好评,7个人得到中评,1个人得到差评,那就势必把精力放在内斗上,而不会全身心地投入外部竞争。”

爱琴沃尔德问微软前工程师布莱恩·寇蒂(Brian Cody),微软是否会根据工作表现对他作出评价。寇蒂说:“一直以来,我是否是一名出色的工程师都不太重要,更重要的是,我要在一众管理人员中冒尖儿。”

错过电子阅读趋势

在微软任职16年的营销经理艾德·麦卡希尔(McCahill)说:“你眼看着Windows Phone现状不佳却无能为力,只能思考这样一个问题:微软是怎么浪费掉Windows CE的领先优势的?那类设备曾经大幅领先,优势多达数年。但他们却弄得一团糟,原因就是官僚主义。”

据爱琴沃尔德介绍,微软早在1998年就开发了一款电子阅读器原型产品,但当技术团队把方案提交给比尔·盖茨(Bill Gates)时,立刻被他否决了,他认为这不符合微软的传统。“他不喜欢那个用户界面,原因是不像Windows。”曾经参与该项目的一位程序员回忆道。

“参与该项目的团队不再直接向盖茨汇报工作,而是被编入了专门为Office开发软件的主要产品团队。”爱琴沃尔德称,“很快,这样一个原本负责梦想和创意的团队,却要为利润患得患失。”该技术团队创始人史蒂夫·斯通(Steve Stone)说:“我们已经不能再集中精力开发对消费者有用的技术了,而是要整天思考‘如何赚钱’这样的问题。”

一位微软Office部门前主管对爱琴沃尔德说,电子阅读器项目被否不仅是因为对盈利急功近利,真正的问题在于触摸屏。“Office是为键盘设计的,不是为触控笔和手指设计的。”他说。

微软高管称,该公司对Windows和Office的过度忠诚屡次导致其未能迎合新兴技术。“Windows就是上帝——一切都要以Windows为准。”斯通对爱琴沃尔德说,“对部门中一些有权有势的人来说,是否在移动计算中提供比PC更清爽的用户体验并不重要,正是他们扼杀了当时的项目。”

与社交网络擦身而过

有一次,MSN Messenger的一位年轻开发者发现,同事的孩子可以用AOL的AIM发布状态更新,微软的产品却不具备这一功能。“正是这一趋势造就了Facebook,人们可以在某个地方发表自己的想法,这是一种持续的意识流。”他对爱琴沃尔德说,“AIM的主要作用不是聊天,而是随时查看好友在做什么。”

当他向老板提出Messenger缺乏短信功能时,那个老男人反驳了他的担忧:他不能理解年轻人为什么会在乎区区几个单词。“他完全不理解,”那位开发者说,“正是因为他不知道或者不相信年轻人对这类应用的使用方式,我们才对这一趋势视若无睹。”

“我觉得微软就是科技界的希尔斯百货(Sears),”微软前营销经理科特·马西(Kurt Massey)说,“在40、50和60年代,希尔斯百货如日中天,但现在却门庭冷落。这就是微软的命运,它再也不酷了。”

“他们曾经嘲笑IBM,但现在,他们却变成了自己曾经鄙视的那种企业。”微软前经理比尔·希尔(Bill Hill)说。(文/新浪科技)

3 billion items in Java Map with 16 GB RAM||用16G内存在Java Map中处理30亿对象

One rainy evening I meditated about memory managment in Java and how effectively Java collections utilise memory. I made simple experiment, how much entries can I insert into Java Map with 16 GB of RAM?

Goal of this experiment is to investigate internal overhead of collections. So I decided to use small keys and small values. All tests were made on Linux 64bit Kubuntu 12.04. JVM was 64bit Oracle Java 1.7.0_09-b05 with HotSpot 23.5-b02. There is option to use compressed pointers (-XX:+UseCompressedOops), which is on by default on this JVM.

First is naive test with java.util.TreeMap. It inserts number into map, until it runs out of memory and ends with exception. JVM settings for this test was -Xmx15G

import java.util.*; 
Map m = new TreeMap();
for(long counter=0;;counter++){
  m.put(counter,"");
  if(counter%1000000==0) System.out.println(""+counter);
}

This example ended at 172 milion entries. Near the end insertion rate slowed down thanks to excesive GC activity. On second run I replaced TreeMap with `HashMap, it ended at 182 milions.

Java default collections are not most memory efficient option. So lets try an memory-optimized . I choosed LongHashMap from MapDB, which uses primitive long keys and is optimized to have small memory footprint. JVM settings is again -Xmx15G

import org.mapdb.*
LongMap m = new LongHashMap();    
for(long counter=0;;counter++){
  m.put(counter,"");
  if(counter%1000000==0) System.out.println(""+counter);
}

This time counter stopped at 276 million entries. Again near the end insertion rate slowed down thanks to excesive GC activity.
It looks like this is limit for heap-based collections, Garbage Collection simply brings overhead.

Now is time to pull out the big gun :-). We can always go of-heap where GC can not see our data. Let me introduce you to MapDB, it provides concurrent TreeMap and HashMap backed by database engine. It supports various storage modes, one of them is off-heap memory. (disclaimer: I am MapDB author).

So lets run previous example, but now with off-heap Map. First are few lines to configure and open database, it opens direct-memory store with transactions disabled. Next line creates new Map within the db.

import org.mapdb.*

DB db = DBMaker
   .newDirectMemoryDB()
   .transactionDisable()
   .make();

Map m = db.getTreeMap("test");
for(long counter=0;;counter++){
  m.put(counter,"");
  if(counter%1000000==0) System.out.println(""+counter);
}

This is off-heap Map, so we need different JVM settings: -XX:MaxDirectMemorySize=15G -Xmx128M. This test runs out of memory at 980 million records.

But MapDB can do better. Problem in previous sample is record fragmentation, b-tree node changes its size on each insert. Workaround is to hold b-tree nodes in cache for short moment before they are inserted. This reduces the record fragmentation to minimum. So lets change DB configuration:

DB db = DBMaker
     .newDirectMemoryDB()
     .transactionDisable()
     .asyncFlushDelay(100)
     .make();

Map m = db.getTreeMap("test");         

This records runs out of memory with 1 738 million records. Speed is just amazing 1.7 bilion items are inserted within 31 minutes.

MapDB can do even better. Lets increase b-tree node size from 32 to 120 entries and enable transparent compression:

   DB db = DBMaker
            .newDirectMemoryDB()
            .transactionDisable()
            .asyncFlushDelay(100)
            .compressionEnable()
            .make();

   Map m = db.createTreeMap("test",120, false, null, null, null);

This example runs out of memory at whipping 3 315 million records. It is slower thanks to compression, but it still finishes within a few hours. I could probably make some optimization (custom serializers etc) and push number of entries to somewhere around 4 billions.

Maybe you wander how all those entries can fit there. Answer is delta-key compression. Also inserting incremental key (already ordered) into B-Tree is best-case scenario and MapDB is slightly optimized for it. Worst case scenario is inserting keys at random order:

UPDATE added latter: there was bit confusion about compression. Delta-key compression is active by default on all examples. In this example I activated aditional zlib style compression.

    DB db = DBMaker
            .newDirectMemoryDB()
            .transactionDisable()
            .asyncFlushDelay(100)
            .make();

    Map m = db.getTreeMap("test");

    Random r = new Random();
    for(long counter=0;;counter++){
        m.put(r.nextLong(),"");
        if(counter%1000000==0) System.out.println(""+counter);
    }

But even with random order MapDB handles to store 651 million records, nearly 4 times more then heap-based collections.

This little excersice does not have much purpose. It is just one of many I do to optimize MapDB. Perhaps most amazing is that insertion speed was actually wery good and MapDB can compete with memory based collections.

地址:http://kotek.net/blog/3G_map

———————————————————————————————————————-

嫌看英文慢,下面有中文翻译:

————————————————————————————————————————

在一个下雨的夜晚,我在思考Java中内存管理的问题,以及Java集合对内存使用的效率情况。我做了一个简单的实验,测试在16G内存条件下,Java的Map可以插入多少对象。

这个试验的目的是为了得出集合的内部上限。所以,我决定使用很小的key和value。所有的测试,都是在64w位linux环境下进行的,操作系统是ubuntu12.04。JVM版本为Oracle Java 1.7.0_09-bo5 (HotSpot 23.5-b02)。在这个JVM中,压缩指针(compressed pointers(-XX:+UseCompressedOops))的选项是默认打开的。

首先是简单的针对java.util.TreeMap的测试。不停向其中插入数字,直到其抛出内存溢出异常。JVM的设置是-xmx15G

?

1

2

3

4

5

6

import java.util.*;

Map m = new TreeMap();

for(long counter=0;;counter++){

  m.put(counter,"");

  if(counter%1000000==0) System.out.println(""+counter);

}

这个用例插入了1 7200 0000条数据。在接近结束的时候,由于高负荷的GC插入效率开始降低。第二次,我用HashMap代替TreeMap,这次插入了182 000 000条数据。

Java默认的集合并不是最高效利用内存的。所以,这回我们尝试最后化内存的测试。我选择了MapDB中的LongHashMap,其使用原始的long key并且对封装的内存占用进行了优化。JVM的设置仍然是-Xmx15G。

?

1

2

3

4

5

6

import org.mapdb.*

LongMap m = new LongHashMap();   

for(long counter=0;;counter++){

  m.put(counter,"");

  if(counter%1000000==0) System.out.println(""+counter);

}

这次,计数器停止在了276 000 000。同样,在插入接近结束的时候,速度开始减慢。看起来这是基于堆的结合的限制所在。垃圾回收带来了瓶颈 。

现在是时候祭出杀手锏了:-)。我们可以采用非基于堆的方式存储,这样GC就不会发现我们的数据。我来介绍一下MapDB,它提供了基于数据库引擎的并发同步的TreeMap和HashMap。它提供了多样化的存储方式,其中一个就是非堆内存的方式。(声明:我是MapDB的作者)。

现在,让我们再跑一下之前的用例,这次采用的是非堆的Map。首先是配置并打开数据库,它打开的直接基于内存存储并且关闭事物的模式。接下来的代码是在这个db中创建一个新的map。

?

01

02

03

04

05

06

07

08

09

10

11

12

import org.mapdb.*

 

DB db = DBMaker

   .newDirectMemoryDB()

   .transactionDisable()

   .make();

 

Map m = db.getTreeMap("test");

for(long counter=0;;counter++){

  m.put(counter,"");

  if(counter%1000000==0) System.out.println(""+counter);

}

这是非堆的Map,所以我们需要不同的JVM配置: -XX:MaxDirectMemorySize=15G -Xmx128M。这次测试在达到980 000 000条记录的时候出现内存溢出。

但是,MapDB还可以优化。之前样例的问题在于记录的破碎分散,b-tree的节点每次插入都要调整它的容量。变通的方案是,将b-tree的节点在其插入前短暂的缓存起来。这使得记录的分散降到最低。所以,我们来改变一下DB的配置:

?

1

2

3

4

5

6

7

DB db = DBMaker

     .newDirectMemoryDB()

     .transactionDisable()

     .asyncFlushDelay(100)

     .make();

 

Map m = db.getTreeMap("test");  

这次记录数达到了 1 738 000 000。速度也是达到了惊人的31分钟完成了17亿数据的插入。

MapDB还能继续优化。我们把b-tree的节点容量从32提升到120并且打开透明(OneCoder理解为对用户不可见的)压缩:

?

1

2

3

4

5

6

7

8

DB db = DBMaker

            .newDirectMemoryDB()

            .transactionDisable()

            .asyncFlushDelay(100)

            .compressionEnable()

            .make();

 

   Map m = db.createTreeMap("test",120, false, null, null, null);

这个用例在大约3 315 000 000条记录时出现内存溢出。由于压缩,他的速度 有所降低,不过还是在几个小时内完成。我还可以进行一些优化(自定义序列化等等) ,使得数据量达到大约40亿。

也许你好奇所有这些记录是怎么存储的。答案就是,delta-key压缩。(OneCoder注:不知如何翻译)。当然,向B-Tree插入已经排好序的递增key是最佳的使用场景,并且MapDB也对此进行了一些小小的 优化。最差的情形就是key是随机的.

后续更新:很多朋友对压缩有一些困惑。在这些用例中,Delta-key 压缩默认都是启用的。在下面的用例中,我又额外开启了zlib方式的压缩:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

DB db = DBMaker

            .newDirectMemoryDB()

            .transactionDisable()

            .asyncFlushDelay(100)

            .make();

 

    Map m = db.getTreeMap("test");

 

    Random r = new Random();

    for(long counter=0;;counter++){

        m.put(r.nextLong(),"");

        if(counter%1000000==0) System.out.println(""+counter);

    }

即使在随机序列情况下,MapDB也可以存储652 000 000条记录,大概4倍于基于堆的集合。

这个简单的试验没有太多的目的。这仅仅是我对MapDB的一种优化。也许,更多的惊喜在于插入效率确实不错并且MapDB可以抗衡基于内存的集合。

原文地址:http://kotek.net/blog/3G_map

OneCoder注:OneCoder仅做翻译,顺便了解一下知识,关于本文,下面的评论中也存在一定的争议,大家可以自行关注。此文,权当开阔视野,不是也很好么。

如非特别注明,本站内容均为OneCoder原创,转载请务必注明作者和原始出处。
本文地址:http://www.coderli.com/translate-java-collections-bigdata-mapdb

 

java.awt 类 EventQueue|| Java之EventQueue用法详解

public class EventQueue

extends Object

EventQueue 是一个与平台无关的类,它将来自于基础同位体类和受信任的应用程序类的事件列入队列。

它封装了异步事件指派机制,该机制从队列中提取事件,然后通过对此 EventQueue 调用 dispatchEvent(AWTEvent) 方法来指派这些事件(事件作为参数被指派)。该机制的特殊行为是与实现有关的。指派实际排入到该队列中的事件(注意,正在发送到 EventQueue 中的事件可以被合并)的惟一要求是:

按顺序。

也就是说,不允许同时从该队列中指派多个事件。

指派顺序与它们排队的顺序相同。

也就是说,如果 AWTEvent A 比 AWTEvent B 先排入到 EventQueue 中,那么事件 B 不能在事件 A 之前被指派。

一些浏览器将不同代码基中的 applet 分成独立的上下文,并在这些上下文之间建立一道道墙。在这样的场景中,每个上下文将会有一个 EventQueue。其他浏览器将所有的 applet 放入到同一个上下文中,这意味着所有 applet 只有一个全局 EventQueue。该行为是与实现有关的。有关更多信息,请参照浏览器的文档。

有关事件指派机制的线程问题,请参阅 AWT Threading Issues

从以下版本开始:

1.1


构造方法摘要

EventQueue()

方法摘要

protected  void

dispatchEvent(AWTEvent event)
指派一个事件。

static AWTEvent

getCurrentEvent()
返回当前正在被 EventQueue(它与正在调用的线程相关)指派的事件。

static long

getMostRecentEventTime()
返回最近事件的时间戳(如果有),该事件从 EventQueue(它与正在调用的线程相关)进行指派。

 AWTEvent

getNextEvent()
从 EventQueue 移除一个事件,并返回它。

static void

invokeAndWait(Runnable runnable)
导致 runnable 的 run 方法在 EventQueue 的指派线程上被调用。

static void

invokeLater(Runnable runnable)
导致 runnable 的 run 方法在 EventQueue 的指派线程上被调用。

static boolean

isDispatchThread()
如果正在调用的线程是当前 AWT EventQueue 的指派线程,则返回 true。

 AWTEvent

peekEvent()
返回 EventQueue 上的第一个事件,而不移除它。

 AWTEvent

peekEvent(int id)
返回指定 id(如果有) 的第一个事件。

protected  void

pop()
停止使用此 EventQueue 来指派事件。

 void

postEvent(AWTEvent theEvent)
将一个 1.1 样式的事件发送到 EventQueue 中。

 void

push(EventQueue newEventQueue)
用指定的事件队列替换现有的 EventQueue。

从类 java.lang.Object 继承的方法

cloneequalsfinalizegetClasshashCodenotifynotifyAlltoStringwaitwaitwait

构造方法详细信息

EventQueue

public EventQueue()

方法详细信息

postEvent

public void postEvent(AWTEvent theEvent)

将一个 1.1 样式的事件发送到 EventQueue 中。如果在队列中存在一个具有相同 ID 和事件源的事件,则调用源 Component 的 coalesceEvents 方法。

参数:

theEvent,java.awt.AWTEvent – 的一个实例,或它的一个子例

抛出:

NullPointerException – 如果 theEvent 为 null


getNextEvent

public AWTEvent getNextEvent()

                      throws InterruptedException

从 EventQueue 移除一个事件,并返回它。在事件被另一个线程发送之前该方法被阻塞。

返回:

下一个 AWTEvent

抛出:

InterruptedException – 如果另一个线程已经中断了此线程


peekEvent

public AWTEvent peekEvent()

返回 EventQueue 上的第一个事件,而不移除它。

返回:

第一个事件


peekEvent

public AWTEvent peekEvent(int id)

返回指定 id(如果有) 的第一个事件。

参数:

id – 所需事件类型的 id

返回:

指定 id 的第一个事件,如果没有这样的事件,则返回 null


dispatchEvent

protected void dispatchEvent(AWTEvent event)

指派一个事件。指派事件的方式取决于事件的类型和事件的源对象的类型:

事件类型

源类型

指派

ActiveEvent

所有

event.dispatch()

其他

Component

source.dispatchEvent(AWTEvent)

其他

MenuComponent

source.dispatchEvent(AWTEvent)

其他

其他

无动作(忽略)

参数:

event – java.awt.AWTEvent 的一个实例或它的一个子类

抛出:

NullPointerException – 如果 event 为 null


getMostRecentEventTime

public static long getMostRecentEventTime()

返回最近事件的时间戳(如果有),该事件从 EventQueue(它与正在调用的线程相关)进行指派。如果具有时间戳的事件当前正在被指派,则返回它的时间戳。如果还没有事件被指派,则返回 EventQueue 的初始化时间。在 JDK 的当前版本中,只有 InputEvent、ActionEvent 和 InvocationEvent 有时间戳;但是,JDK 的未来版本可能将时间戳添加到其他事件类型中。注意,该方法只应该从应用程序事件的指派线程进行调用。如果该方法从另一个线程进行调用,则返回当前系统的时间(由 System.currentTimeMillis() 报告)。

返回:

最后一次 InputEvent 的时间戳,要指派的 ActionEvent 或 InvocationEvent,如果该方法在不同于事件指派线程的线程上调用,则返回 System.currentTimeMillis()

从以下版本开始:

1.4

另请参见:

InputEvent.getWhen()ActionEvent.getWhen()InvocationEvent.getWhen()


getCurrentEvent

public static AWTEvent getCurrentEvent()

返回当前正在被 EventQueue(它与正在调用的线程相关)指派的事件。只有方法需要访问事件时,该方法才有用,但是该方法并不接受对参数的引用。注意,该方法只应该从应用程序的事件指派线程进行调用。如果从另一个线程调用该方法,则返回 null。

返回:

当前正在被指派的事件;如果在线程上调用而不是在指派线程的事件上调用,则返回 null

从以下版本开始:

1.4


push

public void push(EventQueue newEventQueue)

用指定的事件队列替换现有的 EventQueue。任何挂起的事件都被传输到 EventQueue 以备处理。

参数:

newEventQueue – 要使用的 EventQueue(或其子类的) 的实例

抛出:

NullPointerException – 如果 newEventQueue 为 null

另请参见:

pop()


pop

protected void pop()

            throws EmptyStackException

停止使用此 EventQueue 来指派事件。任何挂起的事件都被传输到以前的 EventQueue 以备处理。

警告:为了避免死锁,不要在子类中将该方法声明为 synchronized。

抛出:

EmptyStackException – 如果以前没有对该 EventQueue 执行 push 操作

另请参见:

push(java.awt.EventQueue)


isDispatchThread

public static boolean isDispatchThread()

如果正在调用的线程是当前 AWT EventQueue 的指派线程,则返回 true。使用此调用确保给定的任务正在当前 AWT EventDispatchThread 上执行(或没有执行)。

返回:

如果给定的任务正在当前 AWT EventQueue 的指派线程上运行,则返回 true。


invokeLater

public static void invokeLater(Runnable runnable)

导致 runnable 的 run 方法在 EventQueue 的指派线程上被调用。在所有挂起事件被处理后才发生。

参数:

runnable – Runnable,其 run 方法应该在 EventQueue 上同步执行

从以下版本开始:

1.2

另请参见:

invokeAndWait(java.lang.Runnable)


invokeAndWait

public static void invokeAndWait(Runnable runnable)

                          throws InterruptedException,

                                 InvocationTargetException

导致 runnable 的 run 方法在 EventQueue 的指派线程上被调用。在所有挂起事件被处理后才发生。在这发生之前调用被阻塞。如果从事件指派线程进行调用,则该方法将抛出 Error。

参数:

runnable – Runnable,其 run 方法应该在 EventQueue 上同步执行

抛出:

InterruptedException – 如果另一个线程已经中断了该线程

InvocationTargetException – 如果运行 runnable 时抛出一个 throwable

从以下版本开始:

1.2

另请参见:

invokeLater(java.lang.Runnable)

 

浅谈EventQueue in Swing

最近在看多线程的东西,EventQueue in Swing负责所有AWTEvent(以及其子类)的分发,以后如果要定义自己的ProgressBar可能会用到,先记下来。

EventQueue in Swing简单工作原理

简单来讲,在EventQueue中有一个dispatchThread,这是一个线程类,负责事件的分发,当Queue中有事件的时候,它会摘取前面的事件并分发给相应的对象进行处理,等处理完之后再获取下一个,当Queue中没有事件的时候,线程等待。

当有事件触发时,系统会调用EventQueue的push方法将AWTEvent添加到EventQueue的最后,同时唤醒dispatchThread。

为什么界面会死掉

所以可以看到,Swing的事件分发实际上是同步的,并且都是在dispatchThread这个线程中处理的,也就是说是一个事件一个事件处理的,如果有某一个事件处理的时间非常长的时侯,其他事件就会被堵塞在那里,从现象上看得话,就是界面会死掉,如果界面被其他窗口覆盖之后再回到前面的时侯,会变成一片灰色,这是因为PaintEvent被堵塞而不能被分发出去的缘故。

为什么Modal Dialog(Frame)弹出的时候界面不会死

当在处理事件的时侯如果弹出一个Modal Dialog,那么处理方法会停在那里并等待Modal Dialog销毁,这个时候按照上面的分析,dispatchThread也会停在那里,这样的话其他事件也不会被分发,那么界面也应该会死掉才对。实际上在等待Modal Dialog销毁的过程中,如果能够保证事件可以顺利地分发出去的话,界面当然就不会死。先来看这个例子。

  1. packageeventqueue;
  2. importjava.awt.AWTEvent;
  3. importjava.awt.ActiveEvent;
  4. importjava.awt.Component;
  5. importjava.awt.EventQueue;
  6. importjava.awt.MenuComponent;
  7. importjava.awt.event.ActionEvent;
  8. importjava.awt.event.ActionListener;
  9. importjavax.swing.JButton;
  10. importjavax.swing.JDialog;
  11. publicclassTestEvent{
  12. publicstaticvoidmain(String[]args){
  13. finalJDialogdlg=newJDialog();
  14. dlg.setTitle(“TestEventQueue”);
  15. JButtonbtn=newJButton(“Test”);
  16. dlg.getContentPane().add(btn);
  17. btn.addActionListener(newActionListener(){
  18. public void actionPerformed(ActionEvente){
  19. long now=System.currentTimeMillis();
  20. EventQueue theQueue=dlg.getToolkit().getSystemEventQueue();  
  21. System.out.println(“atleast5000millis”);
  22. while(System.currentTimeMillis()-now<5000l){
  23. try{
  24. //ThisisessentiallythebodyofEventDispatchThread
  25. AWTEvent event=theQueue.getNextEvent();  
  26. Object src=event.getSource();  
  27. if(event instanceof ActiveEvent){
  28. ((ActiveEvent)event).dispatch();
  29. }elseif(src instanceof Component){
  30. ((Component)src).dispatchEvent(event);
  31. }elseif(src instanceof MenuComponent){
  32. ((MenuComponent)src).dispatchEvent(event);
  33. }
  34. }catch(Exceptionex){
  35. ex.printStackTrace();
  36. }
  37. }
  38. System.out.println(“end”);
  39. }
  40. });
  41. dlg.pack();
  42. dlg.show();
  43. }
  44. }

在上面Swing的例子中,当Button的Action被触发,actionPerformed方法执行的时候,会首先帮助EventQueue分发事件,直到最少5秒之后返回,这时可以看到这个事件处理方法至少执行了5秒钟,但是在这个过程中Dialog仍然可以正常工作,只是因为在这5秒之中并非是Sleep,而是在帮助EventQueue分发事件,如果代码改成
Thread.sleep(5000);
的话,界面将会死掉。

所以在Modal Dialog弹出的时候,实际上只要在show方法中能够实现类似上面的代码,保证事件可以正常的分发(同时截获父窗口的一些事件,过滤掉一些触发Action的事件),那么父窗口的界面就不会死掉。

当事件处理方法很长时间才能做完该怎么办

当事件处理方法需要很长时间才能执行完的话,如果需要保证界面不死的话,还是只能用多线程,虽然上面的方法实现了事件处理的时候界面不死,但是这和一般的事件处理是有不同的,上面的方法实际上在处理的时候什么都没有做,而我们一般需要有自己的操作(比如访问数据库,访问网络,读写操作等需要很长时间才能处理完的工作),不可能做到一边在操作一边处理Event分发,这个时候只有新建一个线程才是正道。

不过关于很多EventQueue in Swing和EventDispatchThread的方法都被封装在其实现里面,对外不可视,导致不可能对其进行一些修改,有点不爽。另外在EventQueue中的AWTEvent一般都是给最上层对象的,比如最上层的JDialog或者JFrame,然后由JDialog或者JFrame分发给其他的Component,不过我不知道怎么可以从AWTEvent事件找到真正的拥有者,这一点比较郁闷

AtomicInteger简介

这个类真的非常实用,更重要的是 它确实非常简单:

附上自己的代码,可以自己试试:

AtomicInteger,一个提供原子操作的Integer的类。在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。

 

代码:

package test;

import java.util.concurrent.atomic.AtomicInteger;
/**
* 来看AtomicInteger提供的接口。

//获取当前的值

public final int get()

//取当前的值,并设置新的值

public final int getAndSet(int newValue)

//获取当前的值,并自增

public final int getAndIncrement()

//获取当前的值,并自减

public final int getAndDecrement()

//获取当前的值,并加上预期的值

public final int getAndAdd(int delta)
* @author YangBaoBao
*
*/
public class AtomicIntegerDemo {
public static void main(String[] args) {
AtomicInteger ai=new AtomicInteger(0);
int i1=ai.get();
v(i1);
int i2=ai.getAndSet(5);
v(i2);
int i3=ai.get();
v(i3);
int i4=ai.getAndIncrement();
v(i4);
v(ai.get());

}
static void v(int i)
{
System.out.println(“i : “+i);
}
}

BufferedImage操作图片笔记

BufferedImage是Image的一个子类,BufferedImage生成的图片在内存里有一个图像缓冲区,利用这个缓冲区我们可以很方便的操作这个图片,通常用来做图片修改操作如大小变换、图片变灰、设置图片透明或不透明等。

  1. BufferedImage bufferedImage = ImageIO.read(new FileInputStream(filePath));

 

使图片变灰

    使图片变灰有两种方法,一种是使用现成的类,一种是自己对每个像素进行操纵。

使用现成的类ColorConvertOp,它的作用就是将一个颜色模式的图片转换为另一个颜色模式的图片。颜色模式是诸如RGB颜色模式、灰度颜色模式等决定图片色彩的东西,比如一副RGB颜色模式的图片是彩色,但我们把它复制到一个灰度颜色模式的图片上时,图片就成灰色的了。

 

  1. public BufferedImage getGrayPicture(BufferedImage originalImage)
  2.     {
  3.         BufferedImage grayPicture;
  4.         int imageWidth = originalImage.getWidth();
  5.         int imageHeight = originalImage.getHeight();
  6.         grayPicture = new BufferedImage(imageWidth, imageHeight,
  7.                 BufferedImage.TYPE_3BYTE_BGR);
  8.         ColorConvertOp cco = new ColorConvertOp(ColorSpace
  9.                 .getInstance(ColorSpace.CS_GRAY), null);
  10.         cco.filter(originalImage, grayPicture);
  11.         return grayPicture;
  12.     }

 

 

     自己操纵图片的像素实现图片变灰。图片变灰的通用算法:取出某个像素的r、g、b值,然后重新计算r、g、b值,计算公式为r=r*0.3+g*0.59+b*0.11,g=r,b=g,最后将该rgb值重新写回像素。

可以用下面三个函数

分别取出r、g、b。ColorModel是一个用来将图片某点的rgb值转化为r、g、b以及alpha等值的类。而bufferedImage本身只能取出一个完整的rgb值,无法分离单独的r、g、b等值。

 

 

bufferedImage.getColorModel().getRed(int pixel)

bufferedImage.getColorModel().getGreen(int pixel)

 

bufferedImage.getColorModel().getBlue(int pixel)

但是这里要注意的是使用这种方法取出r、g、b时,有可能弹出一个错误信息——IllegalArgumentException: More than one component per pixel。通常当你使用这个方法操纵jpg等格式的图片时会报这个错误。这是因为某些图片如JPG格式的不支持使用单个int值的像素读取rgb等信息,应该使用Object类型的像素值进行读取,也就是bufferedImage.getColorModel().getGreen(Object indata)

    

  1. public BufferedImage getGrayPicture(BufferedImage originalImage)  
  2.     {  
  3.         int green=0,red=0,blue=0,rgb;  
  4.         int imageWidth = originalImage.getWidth();  
  5.         int imageHeight = originalImage.getHeight();  
  6.         for(int i = originalImage.getMinX();i < imageWidth ;i++)  
  7.             {  
  8.                 for(int j = originalImage.getMinY();j < imageHeight ;j++)  
  9.                 {  
  10. //图片的像素点其实是个矩阵,这里利用两个for循环来对每个像素进行操作  
  11.                     Object data = routeImage.getRaster().getDataElements(i, j, null);//获取该点像素,并以object类型表示  
  12.                     red = routeImage.getColorModel().getRed(data);  
  13.                     blue = routeImage.getColorModel().getBlue(data);  
  14.                     green = routeImage.getColorModel().getGreen(data);  
  15.                     red = (red*3 + green*6 + blue*1)/10;  
  16.                     green = red;  
  17.                     blue = green;  
  18. /* 
  19. 这里将r、g、b再转化为rgb值,因为bufferedImage没有提供设置单个颜色的方法,只能设置rgb。rgb最大为8388608,当大于这个值时,应减去255*255*255即16777216 
  20. */  
  21.                     rgb = (red*256 + green)*256+blue;  
  22.                     if(rgb>8388608)  
  23.                     {  
  24.                         rgb = rgb – 16777216;  
  25.                     }  
  26. //将rgb值写回图片  
  27.     routeImage.setRGB(i, j, rgb);  
  28.                 }  
  29.                   
  30.             }  
  31.              
  32.         return originalImage;     
  33.     }