Archive

Posts Tagged ‘java’

(翻译)Handling null in Java

March 24th, 2010 No comments

原作者:Roy van Rijn
原文地址:http://www.redcode.nl/blog/2010/02/handling-null-in-java/

空值处理是我在jee的项目中遇到的最常见的问题. 但为什么这会是个问题呢? 接下来我们又准备选用何种策略来解决这个问题呢? 在这篇文章中我将尽力找出这个答案.

让我们先来看一段商业逻辑代码,并且我们假设没有空值:

         public BigDecimal getBalance(Person person) {
	    Set<Account> accounts = person.getAccounts();
	    BigDecimal totalBalance = BigDecimal.ZERO;
	    for(Account account: accounts) {
	        totalBalance = totalBalance.add(account.getBalance());
	    }
	    return totalBalance;
	}

这看起来非常的好理解! 但是这不是我们大多数项目中的情况. 通常我们看到的代码是这样:

         public BigDecimal getBalance(Person person) {
	    if(person != null) {
	        Set<Account> accounts = person.getAccounts();
	        if(accounts != null) {
	            BigDecimal totalBalance = BigDecimal.ZERO;
	            for(Account account: accounts) {
	                if(account != null) {
	                    totalBalance = totalBalance.add(account.getBalance());
	                }
	            }
	        }
	        return totalBalance;
	    } else {
	        return null;
	    }
	}

呵呵,这看起来一点也不漂亮! 我们如何去改进呢?

Inversion of logic
第一个策略可以根据我之前写的文章inversion of logic(http://www.redcode.nl/blog/2009/12/inversion_of_logic/). 这里的思想是先退出, 这将提高这个方法的可读性. 让我们看看更具这个原则改进后的代码:

         public BigDecimal getBalance(Person person) {
	    if(person == null || person.getAccounts() == null) {
	        return null;
	    }
	    Set<Account> accounts = person.getAccounts();
	    BigDecimal totalBalance = BigDecimal.ZERO;
	    for(Account account: accounts) {
	        if(account != null) {
	            totalBalance = totalBalance.add(account.getBalance());
	        }
	    }
	    return totalBalance;
	}

这看起来好一点了,简短些,但是还是有我们不想要的”!=”和”==null”的检查

Code by contract
避免空值检查的最好方式是在你的应用中避免空值. 只需要在你的所有的方法返回时非空! 这听起来非常容易并且直接,但是做起来比听起来要困难一些,因为每个方法返回非空并不是我们的习惯.
令人欣慰的是目前有些ide已经实现了@NotNull和@Nullable这两个annotations. 有了这两个annotations你可以通知其他的程序员,你的IDE及代码分析工具:你创建你的方法时的思想:

         @Nullable
	public Person getPerson(Long id) {
	    return something.retrievePerson(id);
	}
 
	public void printPersonName(Long id) {
	    Person person = getPerson(id);
	    System.out.println(person.getName());
	    //Causes warning: getPerson is Nullable, thus this is a possible NPE!
	}

它也可以帮助你清楚的声明,你的方法调用中,参数person非空:

         public void printPersonName(@NotNull Person person) {                
	    System.out.println(person.getName());                        
	    //Very good, we know we won't get a NPE here!                
	}                                                                
 
	public void executeThis() {                                      
	    Person person = null;                                        
	    printPersonName(person);                                     
	    //Causes warning: person might be null, thus can cause a NPE!
	    //Code analysis tools and/or IDE will warn you about this.   
	}

它也可以帮助你修正可能的编码错误:

        @NotNull     
        public Person getPersonFromDatabase(@NotNull Long id) {                            
	    //Use JPQL                                                                     
	    Query query = em.createQuery("SELECT p FROM Person p WHERE p.id = :value");    
	    q.setParameter("value", id);                                                   
	    return q.getSingleResult();                                                    
	    //The IDE will complain about this.                                            
	    //The database might return null, we don't allow returning null in this method.
	}

使用这个方法你多了几分把握. 但是这不是万全之策. 我们必须停下来想一想,空值是从哪里来的?
事实上,当时停止返回空值的时候(这取决于你和你的团队),仍旧有一些没有检查的情况. 例如你使用的外部的apis,框架,ORM-mapper. 所以每次执行非你写的方法的时候,你仍旧不得不手工检查. 但是你务必要做到这一点. 而后的代码你可以不做检查,因为你使用了@NotNull这个annotation. 假如你对上面的Person对象及所有fields这么做了,那么你可以是第一个例子的代码变得漂亮,干净很多. 没有空值检查,它们由annotation约束. 唯一要做的就是添加参数的信息.

        @NotNull
	public BigDecimal getBalance(@NotNull Person person) {
	    Set<Account> accounts = person.getAccounts();
	    BigDecimal totalBalance = BigDecimal.ZERO;
	    for(Account account: accounts) {
	        totalBalance = totalBalance.add(account.getBalance());
	    }
	    return totalBalance;
	}

在我的经验中,这样做很不错, 我已经这样做了有超过一打的次数,甚至在@NotNull和@Nullable出现之前. 在这两个annotations出现之前,我们就在javadoc里添加这样的信息, 但是随着IDE检查的出现,这样的做法就不变得容易很多.

Null object pattern
使用一个null-object是与coding-by-contract的方式完全不同的门路. 这种思想背后的模式是不返回空对象,代替的是返回一个真的对象. 我们的例子就会变成这样:

        public interface Person {                                                                          
 
	    String getName();                      
	    void setName(String name);             
 
	    List<Account> getAccounts();           
 
	    //..etc..                              
	}                                          
 
	public class NullPerson implements Person {
 
	    public String getName() {              
	        return "";                         
	    }                                      
 
	    public void setName(String name) {}    
 
	    public List<Account> getAccounts() {   
	        return Collections.emptyList();    
	    }                                      
	}

这样做后,巨大的好处是你在调用person.getName()的时候是永远安全的,因为即使你得到一个NullPerson,但这个对象也早就存在了. 这个Null-Object很明显是个单例.

         public BigDecimal getBalance(Person person) {
	    Set<Account> accounts = person.getAccounts();
	        //NullPerson returns empty list, no more NPE!
	    BigDecimal totalBalance = BigDecimal.ZERO;
	    for(Account account: accounts) {
	        totalBalance = totalBalance.add(account.getBalance());
	    }
	    return totalBalance;
	}

关于这个模式的更详细阐述,但更一般的版本是由martin Fowler的special case pattern(http://martinfowler.com/eaaCatalog/specialCase.html). 这里不只有一个Null-special情况,你也可以扩展:

        public class UnknownPerson implements Person {
 
	    public String getName() {
	        return "";
	    }
 
	    public void setName(String name) {}
 
	    public List<Account> getAccounts() {
	        return Collections.emptyList();
	    }
 
	}
	public class InvalidatedPerson implements Person {
 
	    public String getName() {
	        return "";
	    }
 
	    public void setName(String name) {}
 
	    public List<Account> getAccounts() {
	        return Collections.emptyList();
	    }
	}

现在你可以返回更多信息,而不只是一个无意义的”null”!

这种模式也有一个问题. 它也没有解决你的问题. 为什么我们会想要计算一个NullPerson的账户总结余呢?当你取得一个person并且是一个NullPerson实例的时候,捕获且适当的处理,而不是一味的继续下面的代码.

Safe null operator
有一段时间,有一种思考,就是通过Coin项目把Safe-null-operator引入java7中. 假如你有Groovy的编程经验,那么你可能见过以下的代码:

         public String getFirstLetterOfName(Person person) {
	    return person?.getName()?.substring(0, 1);
	}

这个思想就是用”?.”来替代”.”. 这个引号标志意味着”假如我们将要访问的对象是空,那么返回空,否则执行下一个方法”.
那么在这个例子中:
假如person为null,那么返回null
假如getName()为空,返回null
最后返回substring(0,1)的结果

假如写成目前的代码形式就是这样:

         public String getFirstLetterOfName(Person person) {
	    if(person == null) {
	        return null;
	    }
	    if(person.getName() == null) {
	        return null;
	    }
	    return person.getName().substring(0, 1);
	}

你也可以返回一个默认的值:

         public void printName(Person person) {
	    System.out.println(person?.getName() ?: "Anonymous");
	}

假如perrson或者getName()是空,那么”?:”操作符就返回默认的字符串.
这看起来非常的不错吧,哈?唯一的问题是,这样的新操作符最终没有被引入到Java7的变更列表中.
有趣的是:你知道为什么”?:”操作符被称为”猫王”操作符么?从侧边看起来它像猫王的一个笑脸,包括他大圈的头发!

Categories: translation Tags: , , ,

一段btrace代码

February 21st, 2010 No comments

最近想要优化一下本地cache,不知道数据的使用情况,故写了一个btrace脚本来做分析,也可以顺便熟悉一下强大的btrace
btrace目前已经到了1.0,可以从下面的地址下载:
https://btrace.dev.java.net/files/documents/8510/135506/btrace-bin.tar.gz

以下是今天写的btrace脚本:

import java.util.Map;
 
import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.BTrace;
import com.sun.btrace.annotations.OnEvent;
import com.sun.btrace.annotations.OnMethod;
import com.sun.btrace.annotations.OnTimer;
import com.sun.btrace.annotations.Property;
 
/**
 * @author chua 2010-2-20 16:36:44
 */
@BTrace
public class CacheProbe {
 
    @Property
    private static Map map = BTraceUtils.newHashMap();
 
    @OnMethod(
        clazz = "com.meichua.sample.model.Cache", 
        method = "/getAllAttributes|getAllLocators/"
    )
    public static void visitCategory() {
        if (!BTraceUtils.containsKey(map, "category")) {
            BTraceUtils.put(map, "category", "yes");
        }
    }
 
    @OnMethod(clazz = "com.meichua.sample.model.Cache", method = "/getAreaMap|getAreaTree/")
    public static void visitArea() {
        if (!BTraceUtils.containsKey(map, "area")) {
            BTraceUtils.put(map, "area", "yes");
        }
    }
 
    .
    .
    .
 
    @OnEvent
    public static void onEvent() {
        BTraceUtils.println("BTrace probe will print the used original data:");
        BTraceUtils.printMap(map);
        BTraceUtils.println("BTrace program exits!");
        BTraceUtils.exit();
    } 
 
    @OnTimer(1000*60*5)
    public static void ontimer() {
        BTraceUtils.println("--------------------------------------:");
        BTraceUtils.printMap(map);
    }
 
}

@BTrace 这个annotation表明这个类是个btrace的脚本
@Property 这个annotation标注的field是可以在JMX client中,如jconsole中可以看到
@OnMethod 这个annotation标注要监控的类中的方法,我的例子中,是一个正则表达式,当然还可以是更复杂的正则表达式
@OnEvent 这个annotation表明事件处理时,打印map中的内容,这个事件,可以在运行btrace脚本的控制台中用ctrl+c,再选择2触发
@OnTimer 这个annotation是一个定时器,有定义的时间触发一次执行,打印map内容,时间单位是毫秒

另外: map的创建,操作,打印必须有BTraceUtils的方法创建,在一个事件中,不能调用任何自己写的方法
运行: btrace <pid> CacheProbe.java

Categories: base Tags: , , , , ,

在ubuntu中安装dtrace

October 16th, 2009 No comments

准备:
下载最新的dtrace for linux的源包
到这个ftp下找一个最新版本,下载,解压
先看一下readme,有关于作者的信息,我贴一下相关信息,以表达对作者的尊敬

Linux port of DTrace
June 2009
Paul D. Fox
fox@crisp.demon.co.uk

http://www.twitter.com/crispeditor

http://www.crisp.demon.co.uk

Blog – latest news and stuff about the dtrace project:
http://www.crisp.demon.co.uk/blog/
Download dtrace tarballs for linux here:
ftp://crisp.dynalias.com/pub/release/website/dtrace

安装/install
1:make all
报错:

1
2
3
4
5
6
BUILD_DIR=build-2.6.28-11-generic tools/build.pl build-2.6.28-11-generic `uname -m`
Sorry - but I cannot find bison or yacc on your system.
You may need to install more packages. See utils/get-deps.pl
for a script to semi-automate this for you.
Continue ? [y/n] n
make: *** [all] 错误 1

事实上,utils/get-deps.pl并不存在,而tools目录下是有,而这个脚本就是用来在ubuntu下install dtrace的,于是
tools/get-deps.pl
你可以看一下这个脚本,其实就是一个安装脚本,他会下载dtrace的一个源包,然后在安装一些依赖的包

1
2
sudo apt-get install zlib1g-dev flex bison \
	elfutils libelf-dev libc6-dev linux-libc-dev

http://khushildep.blogspot.com这个blog上,也指出了ubuntu要安装的包,当然要看到这个blog得翻墙
sudo apt-get install zlib1g-dev bison flex libelf-dev
再次make all,ok了

2: sudo make install

3: sudo make load
安装完成!!!

4: 接下来验证一下dtrace是否可用
先启一个java程序
然后shell中执行:
dtrace -n ‘syscall::read:entry /execname == “java”/ { jstack(); }’

输出:

1
2
3
4
5
6
7
8
9
10
11
12
dtrace: description 'syscall::read:entry ' matched 1 probe
CPU     ID                    FUNCTION:NAME
  0 257149                       read:entry 
              aux[0]: type=32
aux[1]: type=33
aux[2]: type=16
aux[3]: type=6
aux[4]: type=17
aux[5]: type=3
.
.
.

5:下面的地址是dtrace和java的相关资料,可作为入门学习用
http://www.solarisinternals.com/wiki/index.php/DTrace_Topics_Java

Categories: base Tags: , , , ,

一个sudoku的solver

July 31st, 2008 No comments

前段时间看到了sudoku的游戏,被这个游戏所吸引,在www.websudoku.com 上玩了好久.随之也对之产生了兴趣,特写了一个sudoku的solver.

先来介绍一下sudoku,典型的9*9格也称之为9宫格,近年来风靡世界,一个从满智慧的游戏.如下面一个sudoku puzzle

y

^

|

|

|
null
0 —————————————————————–>x

游戏规则:

1:填入1~9的数字(当然这只是9宫格,如果是16*16的,那就是填入1~16的数字)

2:每行不能有重复的数字

3:每列不能有重复的数据

4:每3*3的小方块内不能有重复的数字

这是一个简单的puzzle,预先已填的数字很多,当然玩这个游戏也有技巧,应当先选取已填入数字多的行或列或3*3格开始游戏,当有小格有几个数字都可以填入时,那就要试了.

如上题可以选取x=1 或 x=9 的列开始,解为:

254768931197253684683149752716935428825476193439821567348597216571682349962314875
2 5 4 7 6 8 9 3 1
1 9 7 2 5 3 6 8 4
6 8 3 1 4 9 7 5 2
7 1 6 9 3 5 4 2 8
8 2 5 4 7 6 1 9 3
4 3 9 8 2 1 5 6 7
3 4 8 5 9 7 2 1 6
5 7 1 6 8 2 3 4 9
9 6 2 3 1 4 8 7 5

接下来介绍一下我的java解题方案

1:先loading一个sudoku

2:计算每个空格的优先权,可填入的数字.将sudoku放入stack中

3:从stack中取出一个sudoku,根据优先权和可填入的数字,将一个sudoku分成一个或多个,判断每一个是否已经完成,检查正确性,如还未完成,则检查是否丢弃此sudoku,如果没有完成且还要继续填充,则放入stack

4:接着做3直到完成

基本方案就是这样

网上比较成熟的方案如使用dancing link algorithem,我没有仔细看,大致也就是这样,遍历算法.

csdn上有人用c写的dancing link解决方法,世界上最难的puzzle上,我这个xp2500+的cpu下,需要3.5秒左右

我没有用dancing link算法的java实现来做,所以也就没法对比.

源代码见:

http://meichua.googlecode.com/files/sudoku.rar

Categories: technic Tags: , ,

hbase的搭建

May 6th, 2008 No comments

hbase的搭建
URL:http://hadoop.apache.org/hbase/docs/r0.1.1/api/overview-summary.html

在已经创建的hdfs基础上搭建
1:修改hadoop/contrib/hbase/conf/hbase-env.sh
加入java_home的路径

2:修改hadoop/contrib/hbase/conf/hbase-site.xml,加入如下

1
2
3
4
5
6
7
8
9
10
  <property>
    <name>hbase.master</name>
    <value>10.0.4.121:11100</value>
    <description>The host and port that the HBase master runs at.</description>
  </property>
  <property>
    <name>hbase.rootdir</name>
    <value>hdfs://10.0.4.121:10100/hbase</value>
    <description>The directory shared by region servers.</description>
  </property>

3:启动hbase

1
hadoop/contrib/hbase/bin/start-hbase.sh

4: 查看http://wiki.apache.org/hadoop/Hbase/HbaseShell,进行shell操作

4.1 首先进入shell

1
 hadoop/contrib/hbase/bin/hbase shell

4.2 创建表

1
 CREATE TABLE offer(image_big,image_small);

4.2 插入数据,查询,删除数据
如:

1
2
3
4
5
6
  INSERT INTO offer(image_big:,image_small:) VALUES ('abcdefg','abc') WHERE row = 'testinsert';
  INSERT INTO offer(image_big:,image_small:) VALUES ('hijklmn','hij') WHERE row = 'testinsert';
  INSERT INTO offer(image_big:content,image_big:path,image_small:content,image_small:path) VALUES ('abcdefg','path_big','abc','path_small') WHERE row = 'testinsert';
  INSERT INTO offer(image_big:content,image_big:path,image_small:content,image_small:path) VALUES ('hijklmn','path_big','hij','path_small') WHERE row = 'testinsert';
 
  SELECT * FROM offer WHERE row = 'testinsert';

返回结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 +------------------------+-------------------------+
 | Column                 | Cell                    |
 +------------------------+-------------------------+
 | image_big:             | hijklmn                 |
 +------------------------+-------------------------+
 | image_big:content      | hijklmn                 |
 +------------------------+-------------------------+
 | image_big:path         | path_big                |
 +------------------------+-------------------------+
 | image_small:           | hij                     |
 +------------------------+-------------------------+
 | image_small:content    | hij                     |
 +------------------------+-------------------------+
 | image_small:path       | path_small              |
 +------------------------+-------------------------+
1
 SELECT count(*) FROM offer WHERE row = 'testinsert';

返回:

1
 1 row(s) in set. (0.02 sec)

从上可以看到,虽然我们插入了4条数据,但是结果是1,hbase覆盖了相同的数据,insert2覆盖insert1,insert4覆盖insert2,相当于update,从shell的介绍中我们也看到hql没有提供update
此时的数据结果应该如下:

1
2
3
4
5
6
7
 +----------+--------------------------+---------------------------+
 |          |  Column   image_big      |      Column image_small   |
 |   key    +--------------------------+---------------------------+
 |          |   :   |:content | :path  |  :  |:content|  :path     |
 +-------------------------------------+---------------------------+
 |testinsert|hijklmn|hijklmn  |path_big| hij |  hij   |  path_small|
 +----------+--------------------------+---------------------------+

加入insert加入TIMESTAMP会怎么样呢?

1
2
3
4
5
6
  DELETE * FROM offer WHERE row = 'testinsert';
 
  INSERT INTO offer(image_big:,image_small:) VALUES ('abcdefg','abc') WHERE row = 'testinsert' timestamp '1209982310285';
  INSERT INTO offer(image_big:,image_small:) VALUES ('hijklmn','hij') WHERE row = 'testinsert' timestamp '1209982311285';
  INSERT INTO offer(image_big:content,image_big:path,image_small:content,image_small:path) VALUES ('abcdefg','path_big','abc','path_small') WHERE row = 'testinsert' timestamp '1209982312285';
  INSERT INTO offer(image_big:content,image_big:path,image_small:content,image_small:path) VALUES ('hijklmn','path_big','hij','path_small') WHERE row = 'testinsert' timestamp '1209982313285';

结果无论是

1
  SELECT * FROM offer WHERE row = 'testinsert'

or

1
  SELECT * FROM offer WHERE row = 'testinsert' timestamp '1209982310285';

都只返回

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  +-------------------------+----------------------+
  | Column                  | Cell                 |
  +-------------------------+----------------------+
  | image_big:              | hijklmn              |
  +-------------------------+----------------------+
  | image_big:content       | hijklmn              |
  +-------------------------+----------------------+
  | image_big:path          | path_big             |
  +-------------------------+----------------------+
  | image_small:            | hij                  |
  +-------------------------+----------------------+
  | image_small:content     | hij                  |
  +-------------------------+----------------------+
  | image_small:path        | path_small           |
  +-------------------------+----------------------+

我迷惑了,如hbase Architecture介绍中是有timestamp的,数据按照时间备份的.但这里怎么理解哦…
http://www.mail-archive.com/core-user@hadoop.apache.org/msg00222.html,上面的页面中说到似乎目前还不支持,但是我这里插入是成功的;另外个人理解row和timestamp从数据结果上来说都是index级的,应该是数据本身之外的,那么不显示倒是没啥问题,但是数据好像被覆盖呢?难道目前不支持……
先delete

1
  DELETE * FROM offer WHERE row = 'testinsert';

再select

1
  SELECT * FROM offer WHERE row = 'testinsert';
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  +-------------------------+----------------------+
  | Column                  | Cell                 |
  +-------------------------+----------------------+
  | image_big:              | abcdefg              |
  +-------------------------+----------------------+
  | image_big:content       | abcdefg              |
  +-------------------------+----------------------+
  | image_big:path          | path_big             |
  +-------------------------+----------------------+
  | image_small:            | abc                  |
  +-------------------------+----------------------+
  | image_small:content     | abc                  |
  +-------------------------+----------------------+
  | image_small:path        | path_small           |
  +-------------------------+----------------------+

这个意外的发现,说明数据是有备份的,是不过没有搜索到历史数据,select中的timestamp条件好像没有起作用,每次返回都是最新的数据.架构中说道insert如果没有时间条件,系统默认会加上当前时间.

5 client访问hbase
如上次访问HDFS,引入hbase-site.xml,lib包,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
  package com.chua.hadoop.client;
 
  import java.io.BufferedInputStream;
  import java.io.BufferedOutputStream;
  import java.io.DataInputStream;
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.util.Iterator;
  import java.util.SortedMap;
 
  import org.apache.commons.httpclient.HttpClient;
  import org.apache.commons.httpclient.methods.GetMethod;
  import org.apache.hadoop.hbase.HBaseConfiguration;
  import org.apache.hadoop.hbase.HTable;
  import org.apache.hadoop.io.Text;
 
  /**
   * 类HBase.java的实现描述:TODO 类实现描述
   * @author chua 2008-5-4 下午05:03:33
   */
  public class HBase {
 
      /**
       * @param args
       */
      public static void main(String[] args) throws Exception {
          String domain = "www.dlog.cn";
          String path_s = "/uploads/m/me/meichua/meichua_100.jpg";
          String path_b = "/uploads/m/me/meichua/200804/22094433_tLuyw.jpg";
          byte[] data_s = getData(domain, path_s);
          byte[] data_b = getData(domain,path_b);
 
          HBaseConfiguration config = new HBaseConfiguration();
          HTable table = new HTable(config, new Text("offer"));
          createRecore(table,"chua","image_big",data_b,path_b);
          createRecore(table,"chua","image_small",data_s,path_s);
 
          //取得一个row的所有data,遍历keySet
          SortedMap map = table.getRow(new Text("chua"));
          if(!map.isEmpty()) {
              Iterator it = map.keySet().iterator();
              while(it.hasNext()){
                  System.out.println(it.next());
              }
          }
          //取得某个row的colunmName的data
          byte[] data = table.get(new Text("chua"), new Text("image_big:content"));
          saveAsFile(data,"c:/chua_big.jpg");
      }
 
      public static void createRecore(HTable table,String row, String colunm,byte[] data, String path) throws IOException {
          long lockId = table.startUpdate(new Text(row));
          table.put(lockId, new Text(colunm+":content"), data);
          table.put(lockId, new Text(colunm+":path"), path.getBytes());
          table.commit(lockId);
      }
 
      /**
       * 从网上读取图片
       * @param domain
       * @param path
       * @return
       */
      public static byte[] getData(String domain,String path){
          byte[] dataResource = null;
          try {
              HttpClient client = new HttpClient();
              client.getHostConfiguration().setHost(domain,80,"http");
              GetMethod getMethod = new GetMethod(path);
              int status = client.executeMethod(getMethod);
              if(status == 200) {
                  dataResource = getMethod.getResponseBody();
              }
              getMethod.releaseConnection();
          } catch(Exception e) {  
              System.out.println("Download error"+e);
          }
          return dataResource;
      }
 
      /**
       * 从本地文件读取
       * @param path
       * @return
       */
      public static byte[] getData(String path) {
          File file = new File(path);
          DataInputStream dis = null;
          try {
              dis = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
              int length = dis.available();
              byte[] data = new byte[length];
              dis.read(data);
              return data;
          } catch (Exception e) {
              e.printStackTrace();
              return null;
          }
      }
 
      /**
       * 存到一个文件
       * @param data
       * @param path
       */
      public static void saveAsFile(byte[] data,String path) {
          if(data != null) {
              try {
                  BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(path));
                  for(byte tmp : data) {
                      out.write(tmp);
                  }
                  out.close();
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      }
  }

输出:
image_big:content
image_big:path
image_small:content
image_small:path
以上是一个client访问hbase的例子,比较简单

6 hbase架构介绍

http://wiki.apache.org/hadoop/Hbase/HbaseArchitecture

Categories: technic Tags: , ,