The performance difference is simply because to calculate a SUM, you don't need to store all the data in memory at the same time.
When you issue the query asking for the SUM directly to the database, it can read each record from disk, accumulate the running total in a single variable in memory, then read the next record - it never needs to keep all the records in memory at the same time. More importantly, it doesn't need to send those records across the network to any other server for processing - it only needs to send the resulting SUM as a single number at the end.
In addition, because a SUM over the whole is equal to the SUM of any distinct subsets of the whole, a SUM can be parallelized - e.g. if the data is partitioned, the database can issue multiple queries to be run in different sessions, each will SUM its portion of the data, then the controlling session can simply SUM over the results of each partition.
When you calculate the sum in your Java program using an Array, it must first issue a query to the database asking for all the data it needs; all the data needs to be transported from the database to the app server, and memory needs to be allocated to store all that data. Only after that does your program then iterate over the Array in memory and calculate the Sum; then, it probably needs to deallocate the Array from memory.
If the volume of data is low, the performance difference will probably be insignificant. If the volume is great, however, the difference can be expected to be very significant.