在 MapReduce 開發中,若 Map 輸出或 Reduce 輸入涉及數組類型,直接使用 org.apache.hadoop.io.ArrayWritable 會拋出經典異常:
java.lang.RuntimeException: java.lang.NoSuchMethodException: org.apache.hadoop.io.ArrayWritable.<init>()
根因在於 ArrayWritable 為抽象基類,要求子類在構造時指定數組元素的具體 Writable 類型。官方文檔明確建議:必須創建具體子類並指定元素類型。
以文本數組為例,正確姿勢如下:
import org.apache.hadoop.io.ArrayWritable;
import org.apache.hadoop.io.Text;
public class TextArrayWritable extends ArrayWritable {
public TextArrayWritable() {
super(Text.class); // 指定元素類型為 Text
}
// 便捷構造:直接從 String[] 轉換
public TextArrayWritable(String[] strings) {
super(Text.class);
Text[] texts = new Text[strings.length];
for (int i = 0; i < strings.length; i++) {
texts[i] = new Text(strings[i]);
}
set(texts); // 設置內部數組
}
}
super(ElementClass.class):Hadoop 反射實例化時調用無參構造。String[] → Text[] 轉換邏輯,業務代碼更簡潔。ArrayWritable 要求數組內所有元素類型一致,異構數組需自定義封裝類。public class LogMapper extends Mapper<LongWritable, Text, Text, TextArrayWritable> {
@Override
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
String[] fields = value.toString().split("\t");
// 業務邏輯處理 fields...
context.write(new Text(fields[0]), new TextArrayWritable(fields));
}
}
Reducer 端直接接收 TextArrayWritable,調用 get() 獲取 Writable[],逐元素強轉 Text 即可。
切記:永遠不要直接實例化 ArrayWritable。為每種業務數組類型(Int、Long、Double、自定義 Writable)編寫專用子類,是 MapReduce 類型安全與序列化正確性的基石。