Sum of all the primes less than or equal to N
Sieve of Eratosthenes

The first possibility would be to implement the Sieve of Eratosthenes.  It's one of the more efficient ways to find all primes between 1 and N.  But there are other things we can do with your existing algorithm.  

Initialize with 2


    long sum = 0;
    long primes[] = new long[((int)max/2)+1];
    int index = 0;



But you know the first prime number (at least I hope you do).  So try this 

    if (max &lt; 2) {
        return 0;
    }
    long sum = 2;

    long primes[] = new long[((int)max/2)+1];
    primes[0] = 2;
    int index = 1;


This helps a little now, but it helps a lot later since we know that 2 is the only even prime.  Since all even numbers are divisible by 2 and all primes are only divisible by themselves and 1, 2 is the only possible even prime.  

Check fewer numbers


    for(long counter = 2; counter &lt;= max; counter++){



This checks every number from 2 to max, but we can trivially reduce this to every odd number from 3 to max if we initialize the array with 2.  

    for (long counter = 3; counter &lt;= max; counter += 2) {


I also added some additional spaces, as I find they make it easier to read the code.  

No evens or divisible by three

And we can actually do even better.  Every third odd number is divisible by three.  So 

    if (max &lt; 2) {
        return 0;
    } else if (max == 2) {
        return 2;
    }
    long sum = 5;

    long primes[] = new long[((int)max/2)+1];
    primes[0] = 2;
    primes[1] = 3;
    int index = 2;

    int increment = 4;
    for (long counter = 5; counter &lt;= max; counter += increment) {
         increment = 6 - increment;


Now the increment varies between 2 and 4.  So we have 5, 7, 11 (skipping 9), 13, 17...  So we skip every number that is divisible by three.  And you can never add an even number to an odd number and get an even number, so we skip all the evens as well.  

Don't use a generic isPrime

Your code uses a generic isPrime method that will work regardless of the caller.  You don't need to do that.  


    if(num == 2 || num == 3){
        return true;
    }



You can skip this, as you never pass 2 or 3 to this method.  


    //System.out.println(Arrays.toString(primes));



This is debugging code and shouldn't be sent to review.  


    long primesCount = primes.length;
    for(int i = 0; i &lt; primesCount; i++){
        if(primes[i] !=0 &amp;&amp; num % primes[i] == 0){
            return false;
        }
    }



You can simplify this to just 

    for (long prime : primes) {
        if (prime == 0) {
            return true;
        }

        if (num % prime == 0) {
            return false;
        }
    }


Now it will check that num is not divisible by any number in the primes array.  Once it reaches the first 0, that means that it is done processing and can return true immediately.  

Note that if primes were a List rather than an array, you wouldn't need to check for 0, as the List would only have prime values in it.  Perhaps the performance improvement from not checking for 0 values would outweigh the increased overhead of the List.  


    long range = (long) Math.sqrt((double)num);
    if(primesCount &gt; 0 &amp;&amp; primes[primes.length-1] &lt; range)
    {
        for(long counter = 2; counter &lt;= range; counter++){
            if(num % counter == 0){
                return false;
            }
        }
    }



You don't need this block of code.  You already checked that it's not divisible by any of the primes less than it.  You don't need to check it again with both primes and non-primes.  

It's possible that you could save some time with the following optimizations:  

    long range = (long) Math.sqrt((double)num);
    for (long i = 2; primes[i] &lt;= range; i++) {
        if (num % primes[i] == 0) {
            return false;
        }
    }

    return true;


This relies on there always being at least one prime between range and num in the primes array.  You might have to preload 5 into the primes array to make this work, as this skips past 3 which is greater than range.  Alternatively you could check that primes[i] is not 0, but that would never happen if you start checking with 7.  

Since we don't pass numbers divisible by 2 or 3 to this method, we don't need to attempt to divide by them.  So we start with the third prime, primes[2] which is 5.  

Note that this makes isPrime dangerously fragile.  You may want to make it private rather than public to make it clear that it should only be called under limited circumstances.  Unless performance is a big issue, the previous version is more robust.  And the previous version may be faster anyway.