java8特性汇总

1、常见的函数式接口

1、Function -T作为输入,返回的R作为输出 、被称为函数式接口

Function function = (x) -> {System.out.print(x+": ");return "Function";}; System.out.println(function.apply("hello world"));

2、Predicate -T作为输入,返回的boolean值作为输出 、被称为断言型接口

Predicate pre = (x) ->{System.out.print(x);return false;}; System.out.println(": "+pre.test("hello World"));

3、Consumer - T作为输入,执行某种动作但没有返回值 、被称为消费型接口

Consumer con = (x) -> {System.out.println(x);}; con.accept("hello world");

4、Supplier - 没有任何输入,返回T 、被称为供给型接口

Supplier supp = () -> {return "Supplier";}; System.out.println(supp.get());

5、BinaryOperator -两个T作为输入,返回一个T作为输出,对于“reduce”操作很有用 

BinaryOperator bina = (x,y) ->{System.out.print(x+" "+y);return "BinaryOperator";}; System.out.println(" "+bina.apply("hello ","world"));

 运行结果如下:

hello world:

Function hello World:

false hello world Supplier hello world BinaryOperator

6、关于函数式接口Comparator的疑惑

函数式接口代表的是只能由一个抽象方法,多个类方法或多个默认方法,但是查阅Comparator接口的源码,发现它有两个抽象方法(compare和equals方法),但它又使用了@FunctionalInterface注解,这是为什么?

解答: 因为equals方法是Object的函数,每个类

都继承于Object,由此可见函数是接口中可以定义或重写Object中的函数,但是除此之外的函数只能定义一个。

代码示例: 

@FunctionalInterface
public interface MyFunctionInterface {
    //抖个机灵 java8开始可以在接口中定义变量,并且会默认为final
    String variable = "接口变量(默认final)";
    boolean myFunction(Object o);
    boolean equals(Object o);
}

如果我们再定义一个函数呢?

java8特性汇总_第1张图片

可以看到当我们继续定义一个函数的时候编译器已经提示无法编译了,由此可见我们的判断是正确的,然后用实际例子再来实验一下.

//关于函数是接口中存在继承Object函数的验证
@Test
public void test() {
    MyFunctionInterface myFunctionInterface = (ss) -> {
        System.out.println("自定义函数式接口:" + ss);
        return true;
    };
    boolean objResult = myFunctionInterface.equals("测试");
    boolean myResult = myFunctionInterface.myFunction("测试");
    System.out.println("Object-equals方法:" + objResult);
    System.out.println("---自定义函数式接口:" + myResult);
}
运行结果:
自定义函数式接口:测试
Object-equals方法:false
---自定义函数式接口:true

通过代码可以看出,我们的函数式接口中有一个和Object的equals函数相同参数相同返回值的函数,但是当我们同时调用函数式接口中的自定义函数和equals函数时,最终的返回值是我们自定义函数的值,由此可见java8中只允许定义一个函数实际上是只允许定义一个非静态、非默认以及非继承Object的函数.

实际上关于静态函数和默认函数也是可以定义的

@FunctionalInterface
public interface MyFunctionInterface {
    // java8开始可以在接口中定义变量,并且会默认为final
    tring variable = "接口变量(默认final)";
    boolean myFunction(Object o);
    boolean equals(Object o);
    static String get() {
        return "静态函数";
    }
    static void set() {
        System.out.println("我也是静态函数");
    }
    default void consume() {
        System.out.println("我是默认函数");
    }
    default String sup() {
        return "我也是默认函数";
    }
}

由此延申一下静态函数和默认函数

静态函数:可以直接通过接口名去调用

默认函数:继承该接口的子类都可以调用该函数

2、方法引用

Ⅰ、方法引用的种类

有如下四种方法引用:

种类

举例

1、Reference to a static method

ContainingClass::staticMethodName

2、Reference to an instance method of a particular object

containingObject::instanceMethodName

3、Reference to an instance method of an arbitrary object of a particular type

ContainingType::methodName

4、Reference to a constructor

ClassName::new

一、类名::静态方法

在Integer中有个compare函数是静态的

java8特性汇总_第2张图片

因此这里我们可以直接通过类名调用

@Test
public void staticFunction() {
    Comparator comparator = Integer::compare;
    int result = comparator.compare(1, 2);
    System.out.println(result);
}

二、对象::实例方法

@Test
public void instanceFunction() {
    Consumer con = System.out::println;
    con.accept("实例方法引用,实例为System.out");
}

三、类名::实例方法

在Integer类中还有一个compareTo函数是非静态函数,任意类型的方法引用相对比较复杂,这里我们遵循第四小节使用规则第二条去理解使用

java8特性汇总_第3张图片

@Test
public void TypeInstanceFunction() {
    Integer integer = new Integer(1);
    System.out.println(integer.compareTo(2));
    //若lambda参数列表中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用 ClassName :: method
    Comparator comparator = Integer::compareTo;
    int result = comparator.compare(1, 2);
    System.out.println(result);
}
运行结果:
-1
-1

四、类名::new

在我们需要创建一个对象的时候可以使用构造器方法引用

public void ConstructFunction() {
    Supplier> sup = ArrayList::new;
    List list = sup.get();
}

总结:

1、我们在使用方法引用的时候返回值要和函数式接口返回值一致

2、我们使用特定类型方法引用的时候(类名:普通函数),函数式接口的参数一定要是普通函数的调用方,如果函数式接口有两个参数,那么第一个参数一定是普通函数调用方,第二个则为普通函数的参数

3、Stream Api

java8更新后,Stream流式操作为我们函数式编程提供了更大的可操作性以及强化了我们的代码可读性,尤其是并行流的实现不仅更好的提高了cup的利用率也针对java8之前的fork/join框架做了很好的封装,当我们操作大量数据的时候减少了大量极其复杂的逻辑设计,下面看一下Stream都为我们提供了那些函数以及使用方式是怎么样的。

java8中有两个最为重要的改变。第一个是Lambda表达式,第二个就是Stream Api,Stream是java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查询、过滤和映射数据等操作,使用Stream API对集合数据进行操作,就类似于使用sql执行数据库查询,也可以使用Stream API来执行并行操作,简而言之Stream API提供了一种高效且易于使用的数据处理方式。

一、什么是Stream(流)?

流是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列,集合讲的是数据,流讲的是计算。

注意:

1、Stream 自己不会存储元素

2、Stream 不会改变源对象,相反,他们会返回一个持有结果的新Stream。

3、Stream 操作是延迟执行的。这意味着它会等到需要结果的时候执行。

二、创建Stream

一个源,集合数组等,获取一个流

1、可以通过Collection系列提供的stream()或parallelStream()

2、通过Arrays中静态方法stream()获取数组流

3、通过Stream的of()方法获取流

4、通过Stream的iterate()方法创建无限流

@Test
public void test1() {
    //1、通过Collection 获取流stream() 或者parallelStream()
    List list = new ArrayList<>();
    Stream stream = list.stream();
    
    //2、通过数组Arrays的stream()获取流
    Integer[] i = new Integer[10];
    Stream arrStream = Arrays.stream(i);
    
    //3、通过Stream的of方法获取流
    Stream streamSelf = Stream.of(new ArrayList<>());
    
    //创建无限流(迭代)
    Stream interateStream = Stream.iterate(0, (x) -> x++);
}

三、中间操作

一个中间链操作,对数据源数据进行处理,多个中间操作可以连接起来形成一个流水线,除非流水线上出发终止操作,否则中间操作不会执行任何处理,而在终止操作时一次性全部处理,称为 惰性求值

创建一个员工类

package java8;

import java.util.Objects;

public class Employee {
    private String name;
    private Integer age;
    private Double salary;
    private Status status;

    public Employee(String name, int age, double salary, Status status) {
        this.name = name;
        this.age = age;
        this.salary = salary;
        this.status = status;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return Objects.equals(name, employee.name) &&
                Objects.equals(age, employee.age) &&
                Objects.equals(salary, employee.salary) &&
                status == employee.status;
    }

    @Override
    public int hashCode() {

        return Objects.hash(name, age, salary, status);
    }

    public enum Status {
        FREE,
        BUSY,
        BLOCK
    }

    public Status getStatus() {
        return status;
    }

    public void setStatus(Status status) {
        this.status = status;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Double getSalary() {
        return salary;
    }

    public void setSalary(Double salary) {
        this.salary = salary;
    }
}

//创建员工对象list

List employeeList = Arrays.asList(
        new Employee("Yudia", 18, 9999.99, Employee.Status.FREE),
        new Employee("Williams", 28, 8888.88, Employee.Status.BUSY),
        new Employee("Su", 38, 7777.77, Employee.Status.BLOCK),
        new Employee("Mike", 48, 6666.66, Employee.Status.BUSY),
        new Employee("John", 58, 5555.55, Employee.Status.FREE),
        new Employee("White", 68, 4444.44, Employee.Status.BUSY),
        new Employee("Black", 78, 3333.33, Employee.Status.FREE),
        new Employee("Lucy", 88, 2222.22, Employee.Status.BUSY),
        new Employee("Click", 98, 1111.11, Employee.Status.BLOCK)
);

1、筛选与切片

filter-接受lambda,从流中排除某些元素

limit-截断流,使元素不超过给定个数

skip(n)-跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个则返回一个空流

distinct-筛选,通过流所产生元素的hashCode()和equals()去除重复元素

filter传入一个断言lambda表达式对流进行筛选

Filter、获取工资大于5000的员工

@Test
public void test1() {
    List employees = employeeList.stream()
            .filter(employee -> employee.getSalary() > 5000)
            .collect(Collectors.toList());
    System.out.println(employees);
}
运行结果
[Employee{name='Yudia', age=18, salary=9999.99, status=FREE}, 
Employee{name='Williams', age=28, salary=8888.88, status=BUSY}, 
Employee{name='Su', age=38, salary=7777.77, status=BLOCK}, 
Employee{name='Mike', age=48, salary=6666.66, status=BUSY}, 
Employee{name='John', age=58, salary=5555.55, status=FREE}]

Distinct、获取员工的工作状态,可以看到所有员工的状态重复的已经被去除

@Test
public void test2() {
    List statuses = employeeList.stream()
            .map(Employee::getStatus)
            .distinct()
            .collect(Collectors.toList());
    System.out.println(statuses);
}
运行结果
[FREE, BUSY, BLOCK]

Limit、获取工资大于5000的三个员工

@Test
public void test3() {
    List employees = employeeList.stream()
            .filter(employee -> employee.getSalary() > 5000)
            .limit(3)
            .collect(Collectors.toList());
    System.out.println(employees);
}
运行结果
[Employee{name='Yudia', age=18, salary=9999.99, status=FREE},
 Employee{name='Williams', age=28, salary=8888.88, status=BUSY}, 
 Employee{name='Su', age=38, salary=7777.77, status=BLOCK}]

Skip和limit相对的是 skip可以跳过几个元素,如果流中的元素小于要跳过的数量则返回一个空流

@Test
public void test4() {
    List employees = employeeList.stream()
            .skip(8)
            .collect(Collectors.toList());
    System.out.println(employees);
}
运行结果
[Employee{name='Click', age=98, salary=1111.11, status=BLOCK}]

可以看出我们跳过了流中的前八个元素

2、映射

map-接受lambda,将元素转换成其他形式或提取信息,接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素

flatMap-接受一个函数作为参数,将流中的每个值都当作一个流,最后将所有流汇总

通过map获取所有员工的姓名

@Test public void test5() { List list = employeeList.stream() .map(Employee::getName) .collect(Collectors.toList()); System.out.println(list); } 运行结果 [Yudia, Williams, Su, Mike, John, White, Black, Lucy, Click]

通过flatMap获取所有员工姓名字母

@Test
public void test5() {
    List list = employeeList.stream()
            .map(Employee::getName)
            .collect(Collectors.toList());
    System.out.println(list);
}
运行结果
[Yudia, Williams, Su, Mike, John, White, Black, Lucy, Click]

3、排序

sorted()--自然排序

sorted(Compartor c)--定制排序

自然排序,排列员工年龄

@Test
public void test7() {
    employeeList.stream()
            .map(Employee::getAge)
            .sorted()
            .forEach(System.out::println);
}
结果
18
28
38
48
58
68
78
88
98

定制排序,根据员工工资排序从小到大

@Test
public void test8() {
    employeeList.stream()
            .sorted((e1, e2) -> e1.getSalary().compareTo(e2.getSalary()))
            .forEach(System.out::println);

}
运行结果:
 Employee{name='Click', age=98, salary=1111.11, status=BLOCK}
Employee{name='Lucy', age=88, salary=2222.22, status=BUSY}
Employee{name='Black', age=78, salary=3333.33, status=FREE}
Employee{name='White', age=68, salary=4444.44, status=BUSY}
Employee{name='John', age=58, salary=5555.55, status=FREE}
Employee{name='Mike', age=48, salary=6666.66, status=BUSY}
Employee{name='Su', age=38, salary=7777.77, status=BLOCK}
Employee{name='Williams', age=28, salary=8888.88, status=BUSY}
Employee{name='Yudia', age=18, salary=9999.99, status=FREE}

4、查找与匹配

allMatch-检查是否匹配所有元素

anyMatch-检查是否至少匹配一个元素

noneMatch-检查是否没有匹配所有元素

findFirst-返回第一个元素

findAny-返回当前流中任意元素

count-返回流中元素总个数

max-返回流中最大值

min-返回流中最小值

检查是否所有员工工资大于3000

@Test
public void test9() {
    boolean result = employeeList.stream()
            .allMatch(employee -> employee.getSalary() > 3000);
    System.out.println(result);
}
运行结果:
false

检查所有员工中是否有35岁的员工

@Test
public void test10() {
    boolean result = employeeList.stream()
            .anyMatch(employee -> employee.getAge() == 35);
    System.out.println(result);
}
运行结果:
false

检查所有员工中是否没有叫Mike的

@Test
public void test11() {
    boolean result = employeeList.stream()
            .noneMatch(employee -> "Mike".equals(employee.getName()));
    System.out.println(result);
}
运行结果:
false

返回年龄大于30的第一个员工

@Test
public void test12() {
    Employee e = employeeList.stream()
            .sorted((e1, e2) -> e1.getAge().compareTo(e2.getAge()))//先对员工按年龄顺序排列
            .filter(employee -> employee.getAge() > 30)
            .findFirst()
            .get();
    System.out.println(e);
}
运行结果:
Employee{name='Su', age=38, salary=7777.77, status=BLOCK}

返回任意一个员工、这里我们使用并行流同时取查找

@Test
public void test13() {
    Employee employee = employeeList.parallelStream()
            .findAny().get();
    System.out.println(employee);
}
运行结果:
 Employee{name='White', age=68, salary=4444.44, status=BUSY}

返回所有员工个数

@Test
public void test14() {
    long count = employeeList.stream()
            .count();
    System.out.println(count);
}
运行结果:
9

返回所有员工中最高的工资

@Test
public void test15() {
    double salary = employeeList.stream()
            .max((e1, e2) -> e1.getSalary().compareTo(e2.getSalary()))
            .get()
            .getSalary();
    System.out.println(salary);
}
运行结果:
9999.99

返回所有员工中最小的年龄

@Test
public void test16() {
    int age = employeeList.stream()
            .min((e1, e2) -> e1.getAge().compareTo(e2.getAge()))
            .get()
            .getAge();
    System.out.println(age);
}
运行结果:
18

四、终止操作

一个终止操作,执行中间链操作,并产生结果

1、规约和收集

规约:reduce(T identity,BinaryOperate)/reduce(BinaryOperate),可以将流中的元素反复结合起来得到一个值

获取所有员工工资总和

@Test
public void test17() {
    Double d = employeeList.stream()
            .map(Employee::getSalary)
            .reduce(Double::sum)
            .get();
    System.out.println(d);
}
运行结果:
49999.95000000001

有起始值的规约函数可以防止空指针异常

@Test
public void test18() {
    Double d = employeeList.stream()
            .map(Employee::getSalary)
            .reduce(0.00, Double::sum);
    System.out.println(d);
}
运行结果:
49999.95000000001

收集:collect-将流转换为其他形式,接受一个Collector接口的实现,用于给Stream中元素做汇总的方法

Collector 接口中的方法实现决定了如何对流执行收集操作,如收集到List、Set、Map。并且Collectors实用类提供了很多静态方法,可以方便地创建常见收集器实例

将员工的姓名放到ArrayList和HashSet中

@Test
public void test20() {
    List list = employeeList.stream()
            .map(Employee::getName)
            .collect(Collectors.toCollection(ArrayList::new));

    Set set = employeeList.stream()
            .map(Employee::getName)
            .collect(Collectors.toCollection(HashSet::new));
    System.out.println("ArrayList:" + list);
    System.out.println("HashSet:" + set);
}
运行结果:
ArrayList:[Yudia, Williams, Su, Mike, John, White, Black, Lucy, Click]
HashSet:[Su, Mike, Williams, White, John, Click, Black, Lucy, Yudia]

收集员工总数

@Test
public void test21() {
    long count = employeeList.stream()
            .collect(Collectors.counting());
    System.out.println(count);
}
运行结果:
9   

获取员工年龄平均值

@Test
public void test22() {
    double d = employeeList.stream()
            .collect(Collectors.averagingInt(Employee::getAge));
    System.out.println(d);
}
运行结果:
58.0

获取工资最大值

public void test23() {
    double salary = employeeList.stream()
            .collect(Collectors.maxBy((e1, e2) -> e1.getSalary().compareTo(e2.getSalary())))
            .get()
            .getSalary();
    System.out.println(salary);
}
运行结果:
9999.99

获取工资最小值

@Test
public void test24() {
    double salary = employeeList.stream()
            .collect(Collectors.minBy((e1, e2) -> e1.getSalary().compareTo(e2.getSalary())))
            .get()
            .getSalary();
    System.out.println(salary);
}
运行结果:
9999.99

通过collector函数获取工资最大值、最小值、总和、平均值

@Test
public void test27() {
    //获取最大工资
    double max = employeeList.stream()
            .collect(Collectors.summarizingDouble(Employee::getSalary))
            .getMax();
    //获取最小工资
    double min = employeeList.stream()
            .collect(Collectors.summarizingDouble(Employee::getSalary))
            .getMin();
    //获取工资总和
    double sum = employeeList.stream()
            .collect(Collectors.summarizingDouble(Employee::getSalary))
            .getSum();
    //获取工资平均值
    double avg = employeeList.stream()
            .collect(Collectors.summarizingDouble(Employee::getSalary))
            .getAverage();
    System.out.println("最大工资:" + max);
    System.out.println("最小工资:" + min);
    System.out.println("工资总和:" + sum);
    System.out.println("平均工资:" + avg);
}
运行结果:
最大工资:9999.99
最小工资:1111.11
工资总和:49999.95
平均工资:5555.549999999999

按照员工状态分组

@Test
public void test25() {
    Map> map = employeeList.stream()
            .collect(Collectors.groupingBy(Employee::getStatus));
    System.out.println(map);
}
运行结果:
{BUSY=[
      Employee{name='Williams', age=28, salary=8888.88, status=BUSY}, 
     Employee{name='Mike', age=48, salary=6666.66, status=BUSY}, 
     Employee{name='White', age=68, salary=4444.44, status=BUSY},
     Employee{name='Lucy', age=88, salary=2222.22, status=BUSY}], 
 BLOCK=[
     Employee{name='Su', age=38, salary=7777.77, status=BLOCK}, 
     Employee{name='Click', age=98, salary=1111.11, status=BLOCK}], 
 FREE=[
     Employee{name='Yudia', age=18, salary=9999.99, status=FREE}, 
     Employee{name='John', age=58, salary=5555.55, status=FREE}, 
     Employee{name='Black', age=78, salary=3333.33, status=FREE}]}  

按照员工状态分组后按照年龄段分组

@Test
public void test26() {
    Map>> map = employeeList.stream()
            .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
                if (10 <= e.getAge() && e.getAge() < 30) {
                    return "新手";
                } else if (30 <= e.getAge() && e.getAge() < 50) {
                    return "高级";
                } else {
                    return "专家";
                }
            })));
    System.out.println(map);
}
运行结果:
{
	FREE = {
		新手 = [Employee {name = 'Yudia', age = 18, salary = 9999.99, status = FREE}],
		专家 = [Employee {name = 'John', age = 58, salary = 5555.55, status = FREE}, 
                   Employee {name = 'Black', age = 78, salary = 3333.33, status = FREE
		}]
	}, BUSY = {
		新手 = [Employee {name = 'Williams', age = 28, salary = 8888.88, status = BUSY}],
		专家 = [Employee {name = 'White', age = 68, salary = 4444.44, status = BUSY},
                   Employee {name = 'Lucy', age = 88, salary = 2222.22, status = BUSY}],
		高级 = [Employee {name = 'Mike', age = 48, salary = 6666.66, status = BUSY}]
	}, BLOCK = {
		专家 = [Employee {name = 'Click', age = 98, salary = 1111.11, status = BLOCK}],
		高级 = [Employee {name = 'Su', age = 38, salary = 7777.77, status = BLOCK}]
	}
}

4、Optional类

Optional类(java.util.Optional)是一个容器类,代表一个值存在或者不存在,原来用null标识一个之不存在,现在Optional可以更好的表达这个概念,并且可以避免空指针异常

常用方法:

Optional.of(T t):创建一个Optional实例

Optional.empty():创建一个空的Optional实例

Optional.ofNullable(T t):若t不为null,创建Optional实例,否则创建空实例

isPresent():判断是否包含值

orElse(T t):如果调用对象包含值,返回该值,否则返回t

orElseGet(Suppile s):如果调用对象包含值,返回该值,否则返回s获取的值

map(Function f):如果有对值对其处理,并返回处理后的Optional,否则返回Optional.empty()

flatMap(Function mapper):与map类似,要求返回值必须是Optional

举一个例子,我们获取一个员工对象如果为空则重新创建一个新的对象

@Test
public void test28() {
    Employee employee = (Employee) Optional.ofNullable(null).orElse(new Employee());
    System.out.println("为空时:" + employee);

    Employee employee1 = Optional.ofNullable(new Employee("Click", 98, 1111.11, Employee.Status.BLOCK)).orElse(new Employee());
    System.out.println("不为空时:" + employee1);
}
运行结果:
为空时:Employee{name='null', age=null, salary=null, status=null}
不为空时:Employee{name='Click', age=98, salary=1111.11, status=BLOCK}

5、并行流、串行流

并行流:并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流

java8中将并行进行了优化,我们可以很容易的对数据进行并行操作,StreamAPI可以声明性地同构parallel()与sequential()在并行流与顺序流之间进行切换

java8特性汇总_第4张图片

java8特性汇总_第5张图片

我们通过一个例子计算1~100000000000L的和

java8之前需要继承RecursiveTask类来实现fork/join框架

package forkJoin;

import java.util.concurrent.RecursiveTask;

public class ForkJoinCalculate extends RecursiveTask {

    private long start;
    private long end;
    private static final long THRESHODE = 1000000;

    public ForkJoinCalculate(long start, long end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected Long compute() {
        long length = end - start;
        if (length <= THRESHODE) {
            long sum = 0;
            for (long i = start; i <= end; i++) {
                sum += i;
            }
            return sum;
        } else {
            long middle = (start + end) / 2;
            ForkJoinCalculate left = new ForkJoinCalculate(start, middle);
            left.fork();//拆分子任务 同时压入线程队列
            ForkJoinCalculate right = new ForkJoinCalculate(middle + 1, end);
            right.fork();
            return left.join() + right.join();
        }
    }
}
//java7 forkJoin
@Test
public void test1() {
     //fork join 框架需要forkJoinPool的支持
     Instant start = Instant.now();
     ForkJoinPool pool = new ForkJoinPool();
     ForkJoinTask task = new ForkJoinCalculate(0, 100000000000L);
     long sum = pool.invoke(task);
     System.out.println(sum);
    Instant end = Instant.now();
    System.out.println("java7 forkJoin耗时:" + Duration.between(start, end).toMillis());}
运行结果:
    932356074711512064
    java7 forkJoin耗时:38610

java7 fork/join框架cup利用率

java8特性汇总_第6张图片

//普通for循环
@Test
public void test2() {
    Instant start = Instant.now();
    long sum = 0L;
    for (long i = 0; i <= 100000000000L; i++) {
        sum += i;
    }
    System.out.println(sum);
    Instant end = Instant.now();
    System.out.println("普通for耗时:" + Duration.between(start, end).toMillis());
}
运行结果:
    932356074711512064
    普通for耗时:46514

普通for循环cup利用率

java8特性汇总_第7张图片

//java8 并行流
@Test
public void test3() {
    Instant start = Instant.now();
    long sum = LongStream.rangeClosed(0, 100000000000L)
            .parallel()//切换并行流
            .reduce(0, Long::sum);
    System.out.println(sum);
    Instant end = Instant.now();
    System.out.println("并行流耗时:" + Duration.between(start, end).toMillis());
}
运行结果:
    932356074711512064
    并行流耗时:27743

Java8并行流cup利用率

java8特性汇总_第8张图片

总结:相比单线程for循环,java8并行流以及java8之前的fork/join框架都是用多线程拆分任务的方式更好的利用了cup的执行提高的程序运行效率,但是从实际运行结果来看java8并行流的效率明显会更胜一筹并且相比之前的fork/join框架做了很好的封装,不需要我们再去创建ForkJoinPool,并且也不需要我们设计复杂的递归算法去实现,所以java8并行流的出现会成为我们操作大量数据时的首选。

你可能感兴趣的:(Java,java,java-ee)