Java8新特性二
Posted 钢铁-程序猿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java8新特性二相关的知识,希望对你有一定的参考价值。
文章目录
Java8新特性二
了解Fork/Join框架
Fork/Join框架:就是在必要的情况下,将一个大任务进行拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个小任务的结果进行join汇总。
Fork/Join框架与线程池的区别
采用“工作窃取”模式
当执行新的任务时,它可以将其拆分成更小的任务执行,并将小任务添加到线程队列中,当一个线程在执行任务时获取不到时,从一个随机的线程队列末尾偷一个并把它放在自己的队列中。
import java.util.concurrent.RecursiveTask;
//RecursiveTask有返回值
//RecursiveAcation没有返回值
//Recursive是递归的意思
public class ForkJoinCalculate extends RecursiveTask<Long>
private long start;
private long end;
private final long THRESHOLD = 10000;
public ForkJoinCalculate(long start, long end)
this.start = start;
this.end = end;
@Override
protected Long compute()
long len = end -start;
if(len<=THRESHOLD)
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();
import org.junit.Test;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.LongStream;
/**
* @ClassName TestForkJoin
* @Description: TODO
* @Author renjie
* @Date 2021/5/20
**/
public class TestForkJoin
@Test
public void test()
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<Long> task = new ForkJoinCalculate(0,100000000L);
Long sum = pool.invoke(task);
System.out.println(sum);
Java8并行流
import org.junit.Test;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.LongStream;
/**
* @ClassName TestForkJoin
* @Description: TODO
* @Author renjie
* @Date 2021/5/20
**/
public class TestForkJoin
/**
* Java8并行流
*/
@Test
public void test1()
Instant start = Instant.now();
//串行流
LongStream.rangeClosed(0,100000000000L)
.reduce(0,Long::sum);
Instant end = Instant.now();
System.out.println("串行流耗费时间为:"+ Duration.between(start,end).toMillis());
start = Instant.now();
//并行流
LongStream.rangeClosed(0,100000000000L)
.parallel()
.reduce(0,Long::sum);
end = Instant.now();
System.out.println("并行流耗费时间为:"+ Duration.between(start,end).toMillis());
输出
串行流耗费时间为:38956
并行流耗费时间为:13387
Optional类
Optional容器类的常用方法:
- Optional.of(T t):创建一个Optional实例
- Optional.empty():创建一个空的Optional实例
- Optional.ofNullable(T t):若t不为null,创建Optional实例,否则创建空实例
- isPresent():判断是否包含值
- orElse(T t):如果调用对象包含值,返回该值,否则返回s获取的值。
- map(Function f):如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty()
- flatMap(Function mapper):与map类似,要求返回值必须是Optional
示例
public class TestOptional
@Test
public void test()
Optional<Employee> op = Optional.of(new Employee());
Employee emp = op.get();
System.out.println(emp);
结果
Employeename='null', age=0, salary=0.0, status=null
例子2
public class TestOptional
@Test
public void test1()
Optional<Object> empty = Optional.empty();
System.out.println(empty.get());
结果:抛出异常
java.util.NoSuchElementException: No value present
例子3
public class TestOptional
@Test
public void test1()
Optional<Object> empty = Optional.empty();
//判断是否包含值
if(empty.isPresent())
System.out.println(empty.get());
else
System.out.println("啥都没有");
输出
啥都没有
例子4
有则获取,没有则替换
public class TestOptional
@Test
public void test3()
Optional<Employee> op = Optional.ofNullable(new Employee());
Employee employee = op.orElse(new Employee("sss",20,1111.11,Employee.Status.BUSY));
System.out.println(employee);
输出
Employeename='null', age=0, salary=0.0, status=null
例子5
public class TestOptional
@Test
public void test4()
Optional<Employee> op = Optional.ofNullable(new Employee("sss",20,1111.11,Employee.Status.BUSY));
Optional<String> str = op.map(Employee::getName);
System.out.println(str.get());
输出
sss
例子6
flatMap返回的必须是Optional 进一步避免空指针异常。
public class TestOptional
@Test
public void test5()
Optional<Employee> op = Optional.ofNullable(new Employee("sss",20,1111.11,Employee.Status.BUSY));
Optional<String> str = op.flatMap((e)->Optional.of(e.getName()));
System.out.println(str.get());
输出
sss
例子7
class NewMan
private Optional<Godness> godness = Optional.empty();
public NewMan()
@Override
public String toString()
return "NewMan" +
"godness=" + godness +
'';
public Optional<Godness> getGodness()
return godness;
public void setGodness(Optional<Godness> godness)
this.godness = godness;
public NewMan(Optional<Godness> godness)
this.godness = godness;
public class TestOptional
@Test
public void test6()
Optional<NewMan> op = Optional.ofNullable(null);
String str = getGodnessName(op);
System.out.println(str);
private String getGodnessName(Optional<NewMan> man)
return man.orElse(new NewMan())
.getGodness()
.orElse(new Godness("Miss Li"))
.getName();
输出
Miss Li
接口中的默认方法与静态方法
以前接口中只可以有全局静态常量和抽象方法。
现在还可以有默认方法。使用default修饰符。
java8中允许接口包含具有具体实现的方法,该方法称为“默认方法”,默认方法使用default关键词修饰。
也允许包含静态方法
例如:
public interface MyFunc<T>
T MyFunc(int a);
default String getName()
return "hello java8";
static int getAge()
return 18;
接口默认方法的“类优先”原则
若一个接口中定义了一个默认方法,而另外一个父类或接口中又定义了一个同名的方法时。
- 选择父类中的方法。如果一个父类提供了一个具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略。
- 接口冲突,如果一个父接口提供了一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认),那么必须覆盖该方法来解决冲突。
新时间API
之前的时间相关的类:
- Date
- Calendar:每周第一天默认从星期日开始,是可变的,线程不安全,格式化日期用SimpleDateFormat
新的时间API
不可变,不管怎么变都会产生新的实例。
- 1、java.time下面的众多类,如LocalDate、LocalTime等,时间戳Instant
- 2、时间日期格式化,java.time.format包下的类
旧API中SimpleDateFormat存在的线程安全问题
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;
/**
* @ClassName TestSimpleDateFormat
* @Description: TODO
* @Author renjie
* @Date 2021/5/22
**/
public class TestSimpleDateFormat
public static void main(String[] args) throws ExecutionException, InterruptedException
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
Callable<Date> task = new Callable<Date>()
@Override
public Date call() throws Exception
return sdf.parse("20161218");
;
ExecutorService pool = Executors.newFixedThreadPool(10);
List<Future<Date>> result = new ArrayList<>();
for (int i = 0 ;i<10;i++)
result.add(pool.submit(task));
for(Future<Date> future:result)
System.out.println(future.get());
结果
Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.NumberFormatException: multiple points
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:192)
at TestSimpleDateFormat.main(TestSimpleDateFormat.java:32)
Caused by: java.lang.NumberFormatException: multiple points
java.lang.NumberFormatException: multiple points问题
一般这种问题主要是因为SimpleDateFormat在多线程环境下,是线程不安全的,所以如果你在多线程环境中共享了SimpleDateFormat的实例,比如你在类似日期类中定义了一个全局的SimpleDateFormat对象,这样子肯定会出现上述的报错。
使用ThreadLocal进行改进
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;
class DateFormatThreadLocal
public static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>()
@Override
protected DateFormat initialValue()
return new SimpleDateFormat("yyyyMMdd");
;
public static Date convert(String source) throws ParseException
return df.get().parse(source);
public class TestDateFormatThreadLocal
public static void main(String[] args) throws ExecutionException, InterruptedException
Callable<Date> task = new Callable<Date>()
@Override
public Date call() throws Exception
return DateFormatThreadLocal.convert("20161218");
;
ExecutorService pool = Executors.newFixedThreadPool(10);
List<Future<Date>> result = new ArrayList<>();
for (int i = 0 ;i<10;i++)
result.add(pool.submit(task));
for(Future<Date> future:result)
System.out.println(future.get());
pool.shutdown();
输出
Sun Dec 18 00:00:00 CST 2016
Sun Dec 18 00:00:00 CST 2016
Sun Dec 18 00:00:00 CST 2016
Sun Dec 18 00:00:00 CST 2016
Sun Dec 18 00:00:00 CST 2016
Sun Dec 18 00:00:00 CST 2016
Sun Dec 18 00:00:00 CST 2016
Sun Dec 18 00:00:00 CST 2016
Sun Dec 18 00:00:00 CST 2016
Sun Dec 18 00:00:00 CST 2016
新时间日期API
LocalDate、LocalTime、LocalDateTime
使用LocalDate、LocalTime
以上是关于Java8新特性二的主要内容,如果未能解决你的问题,请参考以下文章