# Why should one use windowing functions for FFT?

So I just revised my pitch calculation algorithm using a harmonic product spectrum algorithm. I was just curious about why this explanation of Harmonic Product Spectrum states that you need to implement a Hanning Window to the data set. What would be the effect of implementing other Window functions on a data set (and then FFTing it)? Which Windowing function is actually the best for frequency detection? Here are the relevant methods I have used in my code:

/**
* Calculates the Frequency based off of the byte array,
* @param bytes The audioData you want to analyze
* @return The calculated frequency in Hertz.
*/
private int getFrequency(byte[] bytes){
double[] audioData = this.bytesToDoubleArray(bytes);
audioData = applyHanningWindow(audioData);
Complex[] complex = new Complex[audioData.length];
for(int i = 0; i<complex.length; i++){
complex[i] = new Complex(audioData[i], 0);
}
Complex[] fftTransformed = FFT.fft(complex);
//return calculateFrequency(fftTransformed);
System.out.println("Max size:" + (fftTransformed.length*getFFTBinSize(fftTransformed.length)/4));
return calculateFundamentalFrequency(fftTransformed,4);
}

private double[] applyHanningWindow(double[] data){
return applyHanningWindow(data, 0, data.length);
}

private double[] applyHanningWindow(double[] signal_in, int pos, int size)
{
for (int i = pos; i < pos + size; i++)
{
int j = i - pos; // j = index into Hann window function
signal_in[i] = (double)(signal_in[i] * 0.5 * (1.0 - Math.cos(2.0 * Math.PI * j / size)));
}
return signal_in;
}

/**
* Harmonic Product Spectrum
* @param fftData
* @param n
* @return
*/
private int calculateFundamentalFrequency(Complex[] fftData, int n){
Complex[][] data = new Complex[n][fftData.length/n];
for(int i = 0; i<n; i++){
for(int j = 0; j<data[0].length; j++){
data[i][j] = fftData[j*(i+1)];
}
}
Complex[] result = new Complex[fftData.length/n];//Combines the arrays
for(int i = 0; i<result.length; i++){
Complex tmp = new Complex(1,0);
for(int j = 0; j<n; j++){
tmp = tmp.times(data[j][i]);
}
result[i] = tmp;
}
//Calculates Maximum Magnitude of the array
double max = Double.MIN_VALUE;
int index = -1;
for(int i = 0; i<result.length; i++){
Complex c = result[i];
double tmp = c.getMagnitude();
if(tmp>max){
max = tmp;;
index = i;
}
}
return index*getFFTBinSize(fftData.length);
}