Hadoop 自定义Writable NullpointerException,hadoopwritable


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;
	}
	
}

通过上面的改进,就不用担心 空指针的问题了。

分享,成长,快乐

转载请注明blog地址:http://blog.csdn.net/fansy1990






java 赋值自定义对象数组 NullPointerException 异常

在for 循环前面加上 pieces = new Piece[width][height]
报空指针应该是因为你没有告诉系统你要申请多大空间的数据,系统就没给你分配空间,没分配空间就找不到,找不到就空指针了。
 

java中用反射, newInstance一个自定义类的时总是javalangNullPointerException,很迷惑

你的数组元素没有初始化。在byTwo[i].aaa =i;前面加上byTwo[i]=new My();并且用大括号括起来,
在byOne[i].aaa =i;前面加上byOne[i]=new My();并且用大括号括起来,就行了。
完整的程序如下:
package myInstance;
import java.lang.reflect.Array;
public class ArrayUtils {
public static <T> T[] newArrayByArrayClass(Class<T[]> clazz, int length) {
return (T[]) Array.newInstance(clazz.getComponentType(), length);
}

public static <T> T[] newArrayByClass(Class<T> clazz, int length) {
return (T[]) Array.newInstance(clazz, length);
}

public static void main(String[] args) {
My[] byTwo = null;
byTwo = newArrayByClass(My.class, 10);//第一种方法
for(int i = 0;i < 10; i ++){
byTwo[i]=new My();
byTwo[i].aaa =i;
}
My[] byOne =null;
byOne = newArrayByArrayClass(My[].class, 10);//第二种方法
for(int i = 0;i < 10; i ++){
byOne[i]=new My();
byOne[i].aaa =i;
}
}
}
//定义“My”类
package myInstance;

public class My
{
public int aaa;
public My(){}
}
 

相关内容

    暂无相关文章