问题导读
1、在定义Hadoop的Writable时候,如何使用到数组?
2、如何不需要通过外部传入,从in中读取即可呢?
3、如何解决空指针的问题?
Hadoop环境:Hadoop2.4
在定义Hadoop的Writable时候,有时需要使用到数组,而不是简单的字符串或者单个的数值。比如下面的代码:
- package test;
-
- import java.io.DataInput;
- import java.io.DataOutput;
- import java.io.IOException;
-
- import org.apache.hadoop.io.WritableComparable;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
-
- public class MyData implements WritableComparable<MyData>,Cloneable {
- private Logger log = LoggerFactory.getLogger(MyData.class);
-
-
- private float[] distance;
-
- public MyData(){// 空指针异常
- set(new float[6]); // 注释掉此行代码,在readFields会有空指针异常
- }
-
-
- public MyData(float[] distance) {
- set(distance);
- }
- public void set(float[] distance) {
- this.distance=distance;
- }
-
-
- @Override
- public void readFields(DataInput arg0) throws IOException {
- for(int i=0;i<distance.length;i++){
- distance[i]=arg0.readFloat();
- }
- }
- @Override
- public void write(DataOutput arg0) throws IOException {
-
- for(int i=0;i<distance.length;i++){
-
- arg0.writeFloat(distance[i]);
- }
- }
- @Override
- public int compareTo(MyData o) {// 当前值小于o则返回负数
-
- float[] oDistance =o.distance;
- int cmp=0;
- for(int i=0;i<oDistance.length;i++){
-
- if(Math.abs(this.distance[i]-oDistance[i])<0.0000000001){
- continue; // 比较下一个
- }
- if(this.distance[i]<oDistance[i]){
- return -1;
- }else{
- return 1;
- }
- }
-
- return cmp;
- }
-
-
- @Override
- public int hashCode(){
- int hashCode =0;
- for(int i=0;i<distance.length;i++){
-
- hashCode=+Float.floatToIntBits(distance[i]);
- }
- return hashCode;
- }
-
-
- public float[] getDistance() {
- return distance;
- }
-
- public void setDistance(float[] distance) {
- this.distance = distance;
- }
-
- }
复制代码
可以看到其无参构造函数里面含有一个初始化的操作,这个初始化的操作限定了其矩阵distance的维度(代码中设置为6),但是一般这个值由外部设置才比较合适,但是在读取的时候,也就是readFields的时候是从这个无参构造函数进入的,这里没有办法设置参数,没有办法在外面初始化这个矩阵的大小,但是不设置又不行,有没有什么办法呢?在Mahout的一些代码中可以看到类似的代码,比如VectorWritable,从VectorWritable可以找到解决这个问题的答案。先看看vectorWritable的一段代码:
- @Override
- public void readFields(DataInput in) throws IOException {
- int flags = in.readByte();
- int size = Varint.readUnsignedVarInt(in);
- readFields(in, (byte) flags, size);
- }
复制代码
通过这段代码可以知道,不一定要通过外部传入,其实可以从in中读取即可。具体如何做呢?定义一个数组distance的大小变量,比如为num,然后把num在write中写入,然后在readFields中先读出,然后再初始化数组distance,这样就不会有刚才的问题了。具体代码如下:
- package test;
-
- import java.io.DataInput;
- import java.io.DataOutput;
- import java.io.IOException;
-
- import org.apache.hadoop.io.WritableComparable;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
-
- public class MyData implements WritableComparable<MyData>,Cloneable {
- private Logger log = LoggerFactory.getLogger(MyData.class);
-
-
- private float[] distance;
- private int num;
- public MyData(){// 此处不再有空指针异常
- // set(new float[6]); // 注释掉此行代码,在readFields不会有空指针异常
- }
-
- public MyData(float[] distance) {
- this.num=distance.length;
- set(distance);
- }
- public void set(float[] distance) {
- this.distance=distance;
- }
-
-
- @Override
- public void readFields(DataInput arg0) throws IOException {
- num = arg0.readInt();
- distance = new float[num];
- for(int i=0;i<distance.length;i++){
- distance[i]=arg0.readFloat();
- }
- }
- @Override
- public void write(DataOutput arg0) throws IOException {
- arg0.writeInt(num);
- for(int i=0;i<distance.length;i++){
-
- arg0.writeFloat(distance[i]);
- }
- }
- @Override
- public int compareTo(MyData o) {// 当前值小于o则返回负数
-
- float[] oDistance =o.distance;
- int cmp=0;
- for(int i=0;i<oDistance.length;i++){
-
- if(Math.abs(this.distance[i]-oDistance[i])<0.0000000001){
- continue; // 比较下一个
- }
- if(this.distance[i]<oDistance[i]){
- return -1;
- }else{
- return 1;
- }
- }
-
- return cmp;
- }
-
-
- @Override
- public int hashCode(){
- int hashCode =0;
- for(int i=0;i<distance.length;i++){
-
- hashCode=+Float.floatToIntBits(distance[i]);
- }
- return hashCode;
- }
-
-
- public float[] getDistance() {
- return distance;
- }
-
- public void setDistance(float[] distance) {
- this.distance = distance;
- }
-
- }
复制代码
通过上面的改进,就不用担心 空指针的问题了。
本文转载自:fansy1990
|