作为一名软件架构师,我更感兴趣的是速度、安全性、可扩展性等方面的新特性或改进。为此,我针对 Java 8 的一些特性做了一些测试。
要点:
- 在遍历 List 时, for ( int i = 0; i < numbers .size(); i++) 比其他任何方法都快得多,无论是并行计算还是串行计算,尽管它看起来很丑。您可以结合 Predicate 减少代码脏度,并以牺牲一些速度为代价提高可重用性,但仍然比其他速度更快,尽管不是最快的。因此,您的选择取决于您对速度的关心程度。
- 在遍历 Map 时,Java 8 更快,但不是很多。总的来说,Java 8 在编码工作和性能方面都胜出。
- 默认函数执行没有区别。
1. 使用 Lambda 表达式遍历列表 VS 不使用
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.elasticsearch.common.netty.util.internal.ThreadLocalRandom;
public class TestLambdaList {
final static List<Integer> numbers = new ArrayList<Integer>();
static int nThreads=4;
static ExecutorService es=Executors.newFixedThreadPool(nThreads);
static void prepare() {
ThreadLocalRandom tlr = ThreadLocalRandom.current();
int c = 10_000_000;
while (--c >= 0) {
numbers.add(tlr.nextInt(10_0000));
}
}
static long countParallel8(){
long s = System.currentTimeMillis();
long t = numbers.parallelStream().filter(e -> (e & 1) == 1).count();
long dif = System.currentTimeMillis() - s;
return dif;
}
static void countParallelOld(long difLambda){
long s = System.currentTimeMillis();
int step=numbers.size()/nThreads;
List<Future<Long>> fs=new ArrayList<Future<Long>>();;
for(int i=0;i<nThreads;i++){
int start=i*step;
int end=(i+1)step;
if(i==nThreads-1){
end=numbers.size();
}
final int endEnclosed=end;
Future<Long> f=es.submit(new Callable<Long>(){
public Long call() throws Exception {
long t=0;
for(int j=start;j<endEnclosed;j++){
if ((numbers.get(j) & 1) == 1) {
t++;
}
}
return t;
}
});
fs.add(f);
}
long t=0;
for(int i=0;i<fs.size();i++){
try {
t+=fs.get(i).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
long dif = System.currentTimeMillis() - s;
System.out.println(Math.round(100.0difLambda/dif)+"\tStream Parallel/(Old Parallel)\t");
}
static long countOddInNovelWay() {
long s = System.currentTimeMillis();
long t = numbers.stream().filter(e -> (e & 1) == 1).count();
long dif = System.currentTimeMillis() - s;
return dif;
}
static void countOddInOldWay(long difLambda) {
long s = System.currentTimeMillis();
long t = 0;
for (int i = 0; i < numbers.size(); i++) {
if ((numbers.get(i) & 1) == 1) {
t++;
}
}
long dif=System.currentTimeMillis()-s;
System.out.println(Math.round(100.0*difLambda/dif)+"\tLambda/(Looping like array)\t");
combine(difLambda,i->(i & 1)==1);
s = System.currentTimeMillis();
t=0;
for (Iterator<Integer> it = numbers.iterator(); it.hasNext();) {
if ((it.next() & 1) == 1) {
t++;
}
}
dif=System.currentTimeMillis()-s;
System.out.println(Math.round(100.0*difLambda/dif)+"\tLambda/(Looping via Iterator)\t");
s = System.currentTimeMillis();
t=0;
for (int n : numbers) {
if ((n & 1) == 1) {
t++;
}
}
dif=System.currentTimeMillis()-s;
System.out.println(Math.round(100.0*difLambda/dif)+"\tLambda/(Looping via for each syntax)\t");
s = System.currentTimeMillis();
t=0;
for (ListIterator<Integer> iter = numbers.listIterator(); iter.hasNext(); ) {
if ((iter.next() & 1) == 1) {
t++;
}
}
dif=System.currentTimeMillis()-s;
System.out.println(Math.round(100.0difLambda/dif)+"\tLambda/(Looping via ListIterator)\t");
}
static void combine(long difLambda, Predicate<Integer> p){
long s = System.currentTimeMillis();
long t = 0;
for (int i = 0; i < numbers.size(); i++) {
if (p.idOdd(i)) {
t++;
}
}
long dif=System.currentTimeMillis()-s;
System.out.println(Math.round(100.0difLambda/dif)+"\tLambda/(Looping Array-Like Combined with Predicate)\t");
}
static interface Predicate<Integer>{
boolean idOdd(Integer i);
}
public static void main(String[] args) {
prepare();
for (int i = 0; i < 10_000; i++) {
//long r=countOddInNovelWay();
//countOddInOldWay(r);
long r=countParallel8();
countParallelOld(r);
}
}
}
Results: (The number is a speed ratio of new way to old way )
298Lambda/(Looping like array)
189Lambda/(Looping Array-Like Combined with Predicate)
99Lambda/(Looping via Iterator)
90Lambda/(Looping via for each syntax)
100Lambda/(Looping via ListIterator)
198Lambda/(Looping like array)
160Lambda/(Looping Array-Like Combined with Predicate)
89Lambda/(Looping via Iterator)
100Lambda/(Looping via for each syntax)
83Lambda/(Looping via ListIterator)
198Lambda/(Looping like array)
160Lambda/(Looping Array-Like Combined with Predicate)
89Lambda/(Looping via Iterator)
80Lambda/(Looping via for each syntax)
92Lambda/(Looping via ListIterator)
488Stream Parallel/(Old Parallel)
252Stream Parallel/(Old Parallel)
488Stream Parallel/(Old Parallel)
252Stream Parallel/(Old Parallel)
232Stream Parallel/(Old Parallel)
488Stream Parallel/(Old Parallel)
488Stream Parallel/(Old Parallel)
291Stream Parallel/(Old Parallel)
279Stream Parallel/(Old Parallel)
463Stream Parallel/(Old Parallel)
252Stream Parallel/(Old Parallel)
321Stream Parallel/(Old Parallel)
2. 使用 Lambda 表达式遍历 Map VS 不使用
Map.forEach 和 Map.compute 比旧方法表现更好,但不是很好,但仍然很酷。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.elasticsearch.common.netty.util.internal.ThreadLocalRandom;
public class TestLambdaList {
final static List<Integer> numbers = new ArrayList<Integer>();
static int nThreads=4;
static ExecutorService es=Executors.newFixedThreadPool(nThreads);
static void prepare() {
ThreadLocalRandom tlr = ThreadLocalRandom.current();
int c = 10_000_000;
while (--c >= 0) {
numbers.add(tlr.nextInt(10_0000));
}
}
static long countParallel8(){
long s = System.currentTimeMillis();
long t = numbers.parallelStream().filter(e -> (e & 1) == 1).count();
long dif = System.currentTimeMillis() - s;
return dif;
}
static void countParallelOld(long difLambda){
long s = System.currentTimeMillis();
int step=numbers.size()/nThreads;
List<Future<Long>> fs=new ArrayList<Future<Long>>();;
for(int i=0;i<nThreads;i++){
int start=i*step;
int end=(i+1)step;
if(i==nThreads-1){
end=numbers.size();
}
final int endEnclosed=end;
Future<Long> f=es.submit(new Callable<Long>(){
public Long call() throws Exception {
long t=0;
for(int j=start;j<endEnclosed;j++){
if ((numbers.get(j) & 1) == 1) {
t++;
}
}
return t;
}
});
fs.add(f);
}
long t=0;
for(int i=0;i<fs.size();i++){
try {
t+=fs.get(i).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
long dif = System.currentTimeMillis() - s;
System.out.println(Math.round(100.0difLambda/dif)+"\tStream Parallel/(Old Parallel)\t");
}
static long countOddInNovelWay() {
long s = System.currentTimeMillis();
long t = numbers.stream().filter(e -> (e & 1) == 1).count();
long dif = System.currentTimeMillis() - s;
return dif;
}
static void countOddInOldWay(long difLambda) {
long s = System.currentTimeMillis();
long t = 0;
for (int i = 0; i < numbers.size(); i++) {
if ((numbers.get(i) & 1) == 1) {
t++;
}
}
long dif=System.currentTimeMillis()-s;
System.out.println(Math.round(100.0*difLambda/dif)+"\tLambda/(Looping like array)\t");
combine(difLambda,i->(i & 1)==1);
s = System.currentTimeMillis();
t=0;
for (Iterator<Integer> it = numbers.iterator(); it.hasNext();) {
if ((it.next() & 1) == 1) {
t++;
}
}
dif=System.currentTimeMillis()-s;
System.out.println(Math.round(100.0*difLambda/dif)+"\tLambda/(Looping via Iterator)\t");
s = System.currentTimeMillis();
t=0;
for (int n : numbers) {
if ((n & 1) == 1) {
t++;
}
}
dif=System.currentTimeMillis()-s;
System.out.println(Math.round(100.0*difLambda/dif)+"\tLambda/(Looping via for each syntax)\t");
s = System.currentTimeMillis();
t=0;
for (ListIterator<Integer> iter = numbers.listIterator(); iter.hasNext(); ) {
if ((iter.next() & 1) == 1) {
t++;
}
}
dif=System.currentTimeMillis()-s;
System.out.println(Math.round(100.0difLambda/dif)+"\tLambda/(Looping via ListIterator)\t");
}
static void combine(long difLambda, Predicate<Integer> p){
long s = System.currentTimeMillis();
long t = 0;
for (int i = 0; i < numbers.size(); i++) {
if (p.idOdd(i)) {
t++;
}
}
long dif=System.currentTimeMillis()-s;
System.out.println(Math.round(100.0difLambda/dif)+"\tLambda/(Looping Array-Like Combined with Predicate)\t");
}
static interface Predicate<Integer>{
boolean idOdd(Integer i);
}
public static void main(String[] args) {
prepare();
for (int i = 0; i < 10_000; i++) {
//long r=countOddInNovelWay();
//countOddInOldWay(r);
long r=countParallel8();
countParallelOld(r);
}
}
}
Results: (The number is a speed ratio of new way to old way )
298Lambda/(Looping like array)
189Lambda/(Looping Array-Like Combined with Predicate)
99Lambda/(Looping via Iterator)
90Lambda/(Looping via for each syntax)
100Lambda/(Looping via ListIterator)
198Lambda/(Looping like array)
160Lambda/(Looping Array-Like Combined with Predicate)
89Lambda/(Looping via Iterator)
100Lambda/(Looping via for each syntax)
83Lambda/(Looping via ListIterator)
198Lambda/(Looping like array)
160Lambda/(Looping Array-Like Combined with Predicate)
89Lambda/(Looping via Iterator)
80Lambda/(Looping via for each syntax)
92Lambda/(Looping via ListIterator)
488Stream Parallel/(Old Parallel)
252Stream Parallel/(Old Parallel)
488Stream Parallel/(Old Parallel)
252Stream Parallel/(Old Parallel)
232Stream Parallel/(Old Parallel)
488Stream Parallel/(Old Parallel)
488Stream Parallel/(Old Parallel)
291Stream Parallel/(Old Parallel)
279Stream Parallel/(Old Parallel)
463Stream Parallel/(Old Parallel)
252Stream Parallel/(Old Parallel)
321Stream Parallel/(Old Parallel)
3. 默认函数 VS 传统静态函数
完全没有显着差异,这很好。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.elasticsearch.common.netty.util.internal.ThreadLocalRandom;
public class TestLambdaList {
final static List<Integer> numbers = new ArrayList<Integer>();
static int nThreads=4;
static ExecutorService es=Executors.newFixedThreadPool(nThreads);
static void prepare() {
ThreadLocalRandom tlr = ThreadLocalRandom.current();
int c = 10_000_000;
while (--c >= 0) {
numbers.add(tlr.nextInt(10_0000));
}
}
static long countParallel8(){
long s = System.currentTimeMillis();
long t = numbers.parallelStream().filter(e -> (e & 1) == 1).count();
long dif = System.currentTimeMillis() - s;
return dif;
}
static void countParallelOld(long difLambda){
long s = System.currentTimeMillis();
int step=numbers.size()/nThreads;
List<Future<Long>> fs=new ArrayList<Future<Long>>();;
for(int i=0;i<nThreads;i++){
int start=i*step;
int end=(i+1)step;
if(i==nThreads-1){
end=numbers.size();
}
final int endEnclosed=end;
Future<Long> f=es.submit(new Callable<Long>(){
public Long call() throws Exception {
long t=0;
for(int j=start;j<endEnclosed;j++){
if ((numbers.get(j) & 1) == 1) {
t++;
}
}
return t;
}
});
fs.add(f);
}
long t=0;
for(int i=0;i<fs.size();i++){
try {
t+=fs.get(i).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
long dif = System.currentTimeMillis() - s;
System.out.println(Math.round(100.0difLambda/dif)+"\tStream Parallel/(Old Parallel)\t");
}
static long countOddInNovelWay() {
long s = System.currentTimeMillis();
long t = numbers.stream().filter(e -> (e & 1) == 1).count();
long dif = System.currentTimeMillis() - s;
return dif;
}
static void countOddInOldWay(long difLambda) {
long s = System.currentTimeMillis();
long t = 0;
for (int i = 0; i < numbers.size(); i++) {
if ((numbers.get(i) & 1) == 1) {
t++;
}
}
long dif=System.currentTimeMillis()-s;
System.out.println(Math.round(100.0*difLambda/dif)+"\tLambda/(Looping like array)\t");
combine(difLambda,i->(i & 1)==1);
s = System.currentTimeMillis();
t=0;
for (Iterator<Integer> it = numbers.iterator(); it.hasNext();) {
if ((it.next() & 1) == 1) {
t++;
}
}
dif=System.currentTimeMillis()-s;
System.out.println(Math.round(100.0*difLambda/dif)+"\tLambda/(Looping via Iterator)\t");
s = System.currentTimeMillis();
t=0;
for (int n : numbers) {
if ((n & 1) == 1) {
t++;
}
}
dif=System.currentTimeMillis()-s;
System.out.println(Math.round(100.0*difLambda/dif)+"\tLambda/(Looping via for each syntax)\t");
s = System.currentTimeMillis();
t=0;
for (ListIterator<Integer> iter = numbers.listIterator(); iter.hasNext(); ) {
if ((iter.next() & 1) == 1) {
t++;
}
}
dif=System.currentTimeMillis()-s;
System.out.println(Math.round(100.0difLambda/dif)+"\tLambda/(Looping via ListIterator)\t");
}
static void combine(long difLambda, Predicate<Integer> p){
long s = System.currentTimeMillis();
long t = 0;
for (int i = 0; i < numbers.size(); i++) {
if (p.idOdd(i)) {
t++;
}
}
long dif=System.currentTimeMillis()-s;
System.out.println(Math.round(100.0difLambda/dif)+"\tLambda/(Looping Array-Like Combined with Predicate)\t");
}
static interface Predicate<Integer>{
boolean idOdd(Integer i);
}
public static void main(String[] args) {
prepare();
for (int i = 0; i < 10_000; i++) {
//long r=countOddInNovelWay();
//countOddInOldWay(r);
long r=countParallel8();
countParallelOld(r);
}
}
}
Results: (The number is a speed ratio of new way to old way )
298Lambda/(Looping like array)
189Lambda/(Looping Array-Like Combined with Predicate)
99Lambda/(Looping via Iterator)
90Lambda/(Looping via for each syntax)
100Lambda/(Looping via ListIterator)
198Lambda/(Looping like array)
160Lambda/(Looping Array-Like Combined with Predicate)
89Lambda/(Looping via Iterator)
100Lambda/(Looping via for each syntax)
83Lambda/(Looping via ListIterator)
198Lambda/(Looping like array)
160Lambda/(Looping Array-Like Combined with Predicate)
89Lambda/(Looping via Iterator)
80Lambda/(Looping via for each syntax)
92Lambda/(Looping via ListIterator)
488Stream Parallel/(Old Parallel)
252Stream Parallel/(Old Parallel)
488Stream Parallel/(Old Parallel)
252Stream Parallel/(Old Parallel)
232Stream Parallel/(Old Parallel)
488Stream Parallel/(Old Parallel)
488Stream Parallel/(Old Parallel)
291Stream Parallel/(Old Parallel)
279Stream Parallel/(Old Parallel)
463Stream Parallel/(Old Parallel)
252Stream Parallel/(Old Parallel)
321Stream Parallel/(Old Parallel)