java8新特性

1.对接口的改变

   增加了default方法(属于接口实现类实例)和static方法(属于接口) 

   注意:1.接口之间静态方法不能继承,但是静态字段可以继承      

public interface Class1 {
     int i=1;
    static void test1(){
        System.out.println("Class1.test1");
    }
    default void test2(){
        System.out.println("Class1.test2");
    }
}
View Code
public interface Class2 extends Class1{
}
View Code

              2.一个类实现了两个有同名default方法的接口时候会报错,因为接口default方法属于接口实现类实例,如果可以那么实现类对象调用这个方法的时候不知道调用哪个了。解决办法实现类重写这个方法即可

  

package com.jiuzhouzhi.defaultstatic;

/**
 * @ClassName Inter
 * @Description
 * @Author 刘志红
 * @Date 2018/9/12
 **/
public interface Inter1 {
    default String get(){
        return "Inter1";
    }
    static void hello(){
        System.out.println("hello");
    }
}

package com.jiuzhouzhi.defaultstatic;

public interface Inter2 {
    default String get() {
        return "Inter2";
    }
}

package com.jiuzhouzhi.defaultstatic;

/**
 * @ClassName Impl2
 * @Description
 * @Author 刘志红
 * @Date 2018/9/12
 **/
public class Impl2 implements Inter1,Inter2 {
    @Override
    public String get() {
        return Inter1.super.get();
    }
}
 @Test
    public void test2(){
        Impl2 imp2=new Impl2();
        System.out.println(imp2.get());
        Inter1 inter1=new Impl2();
        System.out.println(inter1.get());
        Inter2 inter2=new Impl2();
        System.out.println(inter2.get());
    }
View Code

 

此时的结果都是Inter1

           3.类优先原则(下面只举了一个接口,也可以实现多个有同名默认方法的接口)这时候接口中的方法会被屏蔽

package com.jiuzhouzhi.defaultstatic;

/**
 * @ClassName FatherClass
 * @Description
 * @Author 刘志红
 * @Date 2018/9/12
 **/
public class FatherClass {
    public String get(){
        return "FatherClass";
    }
}
View Code
package com.jiuzhouzhi.defaultstatic;

/**
 * @ClassName Inter
 * @Description
 * @Author 刘志红
 * @Date 2018/9/12
 **/
public interface Inter1 {
    default String get(){
        return "Inter1";
    }
    static void hello(){
        System.out.println("hello");
    }
}
View Code
package com.jiuzhouzhi.defaultstatic;

/**
 * @ClassName Impl
 * @Description
 * @Author 刘志红
 * @Date 2018/9/12
 **/
public class Impl extends FatherClass implements Inter1{
}
View Code

 

@Test
    public void test1(){
        Impl impl=new Impl();
        System.out.println(impl.get());
        FatherClass fatherClass=new Impl();
        System.out.println(fatherClass.get());
        Inter1 inter1=new Impl();
        System.out.println(inter1.get());
    }
View Code

上面的结果都是“FatherClass

2.函数式编程-->Lambda表达式

lambda表达式可以看成一个简化版的匿名内部类,需要函数式接口的支持,什么是函数式接口?简单地说,接口中若只包含一个抽象方法,则称该接口为函数式接口。可以在接口前使用注解@FunctionalInterface检查该接口是否为函数式接口。

函数式编程的好处:将行为作为参数就行传递,使代码产生质变。

package simple;
/**
 * @ClassName Caculate
 * @Description
 * @Author 刘志红
 * @Date 2019/3/25
 **/
public interface Caculate {
    Integer result(Integer num);
}
package simple;
/**
 * @ClassName Test
 * @Description
 * @Author 刘志红
 * @Date 2019/3/25
 **/
public class Test {
    public static Integer getVal(Integer num,Caculate caculate){
        return caculate.result(num);
    }
    public static void main(String[] args) {
        System.out.println(getVal(100, x->100+x));
        System.out.println(getVal(20, x->x*x));
    }
}
View Code

从上面的代码我们可以看出,有了函数式编程,使代码变的简单灵活,我们不需要具体的实现,而是根据具体的需要在参数中传递即可。

3.四大接口

java8的java.util.funciton包下提供了四大接口。我们从上面可以了解到,我们要实现功能需要定制接口。为了更加简单,java8为我们提供了四类接口,另外还有一些拓展的接口。

 1)Consumer<T>   

接收一个参数并且没有返回值

package java.util.function;

import java.util.Objects;

/**
 * Represents an operation that accepts a single input argument and returns no
 * result. Unlike most other functional interfaces, {@code Consumer} is expected
 * to operate via side-effects.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #accept(Object)}.
 *
 * @param <T> the type of the input to the operation
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);

    /**
     * Returns a composed {@code Consumer} that performs, in sequence, this
     * operation followed by the {@code after} operation. If performing either
     * operation throws an exception, it is relayed to the caller of the
     * composed operation.  If performing this operation throws an exception,
     * the {@code after} operation will not be performed.
     *
     * @param after the operation to perform after this operation
     * @return a composed {@code Consumer} that performs in sequence this
     * operation followed by the {@code after} operation
     * @throws NullPointerException if {@code after} is null
     */
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}
View Code
例如:
package simple;
import java.util.function.Consumer;
/**
 * @ClassName Test
 * @Description
 * @Author 刘志红
 * @Date 2019/3/25
 **/
public class Test {
  public static void consumer(Integer num, Consumer<Integer> consumer){
      consumer.accept(num);
  }
    public static void main(String[] args) {
      consumer(100, x-> System.out.println("大保健消费了"+x));
    }
}
View Code

 2)Supplier<T>

没有参数返回一个结果

package java.util.function;

/**
 * Represents a supplier of results.
 *
 * <p>There is no requirement that a new or distinct result be returned each
 * time the supplier is invoked.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #get()}.
 *
 * @param <T> the type of results supplied by this supplier
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}
View Code

 例如:

package simple;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
/**
 * @ClassName Test
 * @Description
 * @Author 刘志红
 * @Date 2019/3/25
 **/
public class Test {
 public static List<Integer> supply(Integer num, Supplier<Integer> supplier){
     List<Integer>list=new ArrayList<>();
     for (int i = 0; i <num ; i++) {
         list.add(supplier.get());
     }
    return  list;
 }
    public static void main(String[] args) {
        List<Integer> supply = supply(5, () -> (int) (Math.random() * 100));
        for (Integer i :
                supply) {
            System.out.println(i);
        }
    }
}
View Code

 3)Function<T,R>   

接收一个类型参数,返回另一个参数类型结果

package java.util.function;

import java.util.Objects;

/**
 * Represents a function that accepts one argument and produces a result.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #apply(Object)}.
 *
 * @param <T> the type of the input to the function
 * @param <R> the type of the result of the function
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Function<T, R> {

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);

    /**
     * Returns a composed function that first applies the {@code before}
     * function to its input, and then applies this function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     * @param <V> the type of input to the {@code before} function, and to the
     *           composed function
     * @param before the function to apply before this function is applied
     * @return a composed function that first applies the {@code before}
     * function and then applies this function
     * @throws NullPointerException if before is null
     *
     * @see #andThen(Function)
     */
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    /**
     * Returns a composed function that first applies this function to
     * its input, and then applies the {@code after} function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     * @param <V> the type of output of the {@code after} function, and of the
     *           composed function
     * @param after the function to apply after this function is applied
     * @return a composed function that first applies this function and then
     * applies the {@code after} function
     * @throws NullPointerException if after is null
     *
     * @see #compose(Function)
     */
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    /**
     * Returns a function that always returns its input argument.
     *
     * @param <T> the type of the input and output objects to the function
     * @return a function that always returns its input argument
     */
    static <T> Function<T, T> identity() {
        return t -> t;
    }
}
View Code

 例如:

package simple;
import java.util.function.Function;
/**
 * @ClassName Test
 * @Description
 * @Author 刘志红
 * @Date 2019/3/25
 **/
public class Test {
    static class Employee {
        private Long id;
        private String name;
        private double salary;
        public Long getId() {
            return id;
        }
        public void setId(Long id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public double getSalary() {
            return salary;
        }
        public void setSalary(double salary) {
            this.salary = salary;
        }
        public Employee(Long id, String name, double salary) {
            this.id = id;
            this.name = name;
            this.salary = salary;
        }
    }
    public static Double function(Employee e, Function<Employee,Double> function) {
       return  function.apply(e);
    }
    public static void main(String[] args) {
        double salary=function(new Employee(1l, "liuzhihong", 10000.0), x->x.getSalary());
        System.out.println(salary);
    }
}
View Code

 4)Predicate<T> 

 传入一个参数,返回一个boolean值

package java.util.function;

import java.util.Objects;

/**
 * Represents a predicate (boolean-valued function) of one argument.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #test(Object)}.
 *
 * @param <T> the type of the input to the predicate
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);

    /**
     * Returns a composed predicate that represents a short-circuiting logical
     * AND of this predicate and another.  When evaluating the composed
     * predicate, if this predicate is {@code false}, then the {@code other}
     * predicate is not evaluated.
     *
     * <p>Any exceptions thrown during evaluation of either predicate are relayed
     * to the caller; if evaluation of this predicate throws an exception, the
     * {@code other} predicate will not be evaluated.
     *
     * @param other a predicate that will be logically-ANDed with this
     *              predicate
     * @return a composed predicate that represents the short-circuiting logical
     * AND of this predicate and the {@code other} predicate
     * @throws NullPointerException if other is null
     */
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }

    /**
     * Returns a predicate that represents the logical negation of this
     * predicate.
     *
     * @return a predicate that represents the logical negation of this
     * predicate
     */
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }

    /**
     * Returns a composed predicate that represents a short-circuiting logical
     * OR of this predicate and another.  When evaluating the composed
     * predicate, if this predicate is {@code true}, then the {@code other}
     * predicate is not evaluated.
     *
     * <p>Any exceptions thrown during evaluation of either predicate are relayed
     * to the caller; if evaluation of this predicate throws an exception, the
     * {@code other} predicate will not be evaluated.
     *
     * @param other a predicate that will be logically-ORed with this
     *              predicate
     * @return a composed predicate that represents the short-circuiting logical
     * OR of this predicate and the {@code other} predicate
     * @throws NullPointerException if other is null
     */
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

    /**
     * Returns a predicate that tests if two arguments are equal according
     * to {@link Objects#equals(Object, Object)}.
     *
     * @param <T> the type of arguments to the predicate
     * @param targetRef the object reference with which to compare for equality,
     *               which may be {@code null}
     * @return a predicate that tests if two arguments are equal according
     * to {@link Objects#equals(Object, Object)}
     */
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}
View Code

 例如:

package simple;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
/**
 * @ClassName Test
 * @Description
 * @Author 刘志红
 * @Date 2019/3/25
 **/
public class Test {
    public static List<String> predicate(String[] str, Predicate<String> predicate) {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < str.length; i++) {
            if (predicate.test(str[i])) {
                list.add(str[i]);
            }
        }
        return list;
    }
    public static void main(String[] args) {
        String[] strs={"aaaaaaa","bbbbbbb","cccc","dddd","ee"};
        List<String> list = predicate(strs, x -> x.length() > 4);
        for (String str :
                list) {
            System.out.println(str);
        }
    }
}
View Code

 5)拓展接口

除了上面的四种接口外java8还提供了一些拓展接口

4.方法引用与构造器引用

实际就是Lambda表达式的简化版。其实是个匿名内部类。说白了就是一个接口的实现类。

 1)方法引用

        1.对象::实例方法名  典型例子System.out::println

 //对象::方法名    println方法的参数列表和返回值类型,与Consumer<String>的accept参数列表和返回值类型一致
        PrintStream out = System.out;
        Consumer<String> consumer=x->out.println(x);
        consumer.accept("hello");

        PrintStream out1 = System.out;
        Consumer<String> consumer1=out1::println;
        // Consumer<String> consumer1=System.out::println;
        consumer1.accept("world");
View Code

        2.类::静态方法名

//类::静态方法名  
        
      Comparator<Integer> comparator=(x,y)->Integer.compare(x, y);
      
      Comparator<Integer> compare = Integer::compare;
View Code

       注意:1、2需要满足的条件是 Lambda中调用的方法中返回值类型和参数列表类型,要与函数式接口的方法返回值类型和参数列表类型一样。 为啥呢?返回值类型一样很明显因为方法引用本身就是接口的一种实现,而参数列表要求一致,我自己的理解新语法底层写的时候为了分清参数所以规定成这样的(如果参数顺序不一样可能再底层会分不清参数)。

        3 .类::实例方法名     

public static void main(String[] args) {
      //类::实力方法
        BiPredicate<String,String> bp=(x,y)->x.equals(y);
        System.out.println(bp.test("hello", "hello"));

        BiPredicate<String,String> bp2=String::equals;
        System.out.println(bp2.test("hello", "hello"));
View Code

       注意:通过类名掉用实例方法,显然不能直接调用。而且我们通过例子发现:显然参数列表不满足1、2的规则。所以它有自己的语法:第一个参数是类实例,第二个参数是类实例中方法的参数,返回值类型和1、2满足同样的规则。

 2)构造器引用

   类名::new    构造器引用显然是创建对象,所以返回值类型肯定是这个类。构造器的参数列表要与函数式接口一致。

package com.jiuzhouzhi.lambda;

import java.util.Objects;


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

    public Employee() {
    }

    public Employee(String name, Integer age, Double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

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

    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;
    }

    public Employee(String name) {
        this.name = name;
    }

    public Employee(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public enum Status {
        FREE, BUSY, VOCATION;
    }

    @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);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age, salary);
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", salary=" + salary +
                ", status=" + status +
                '}';
    }
}
View Code 
package simple;
import com.jiuzhouzhi.lambda.Employee;

import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
 * @ClassName Test
 * @Description
 * @Author 刘志红
 * @Date 2019/3/26
 **/
public class Test {
    public static void main(String[] args) {
      //构造器引用
         //无参构造
        //--lambda--
        Supplier<Employee> supplier=()->new Employee();
        //---构造引用--
        Supplier<Employee> supplier1=Employee::new;
        Employee employee = supplier1.get();
        //有参构造
        //---lambda---
        Function<String,Employee> function=x->new Employee(x);
        //---构造器引用---
        Function<String,Employee> function1=Employee::new;
        Employee xaoqiang = function1.apply("小强");

        //---lambda---
        BiFunction<String,Integer,Employee> function2=(x,y)->new Employee(x,y);
        //---构造器引用---
        BiFunction<String,Integer,Employee> function3=Employee::new;
        Employee wangcai = function3.apply("旺财", 22);
        //三个或者以上的构造器,需要自己写接口

       //数组对象
        Function<Integer,String[]> function4=x->new String[x];

        Function<Integer,String[]> function5=String[]::new;
        String[] apply = function5.apply(3);
        System.out.println(apply.length);

    }
}
View Code

5.Stream流

  有关内容转自 https://blog.csdn.net/justloveyou_/article/details/79562574

  前提Join/Fork

 引用http://ifeve.com/talk-concurrency-forkjoin/

1.Fork/Join框架原理

Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得 到大任务结果的框架。 我们再通过Fork和Join这两个单词来理解下Fork/Join框架,Fork就是把一个大任务切分为若干子任务并行的执行,Join就是合并这些子 任务的执行结果,最后得到这个大任务的结果。比如计算1+2+。。+10000,可以分割成10个子任务, 每个子任务分别对1000个数进行求和,最终汇总这10个子任务的结果,对于数据量特别大的话 Fork-Join执行效率会比普通方式高

 

2.采用工作窃取算法 工作窃取(work-stealing)算法是指某个线程从其他队列里窃取任务来执行。

那么为什么需要使用工作窃取算法呢?假如我们需要做一个比较大的任务,我们可以把这个任务分割为若干互不依赖的子任务, 为了减少线程间的竞争,于是把这些子任务分别放到不同的队列里,并为每个队列创建一个单独的线程来执行队列里的任务, 线程和队列一一对应,比如A线程负责处理A队列里的任务。但是有的线程会先把自己队列里的任务干完, 而其他线程对应的队列里还有任务等待处理。干完活的线程与其等着,不如去帮其他线程干活, 于是它就去其他线程的队列里窃取一个任务来执行。而在这时它们会访问同一个队列,所以为了减少窃取任务线程和被窃取任务线程之间的竞争, 通常会使用双端队列,被窃取任务线程永远从双端队列的头部拿任务执行,而窃取任务的线程永远从双端队列的尾部拿任务执行。

工作窃取算法的优点是充分利用线程进行并行计算,并减少了线程间的竞争,其缺点是在某些情况下还是存在竞争, 比如双端队列里只有一个任务时。并且消耗了更多的系统资源,比如创建多个线程和多个双端队列

 3.Fork/Join框架的介绍 我们已经很清楚Fork/Join框架的需求了,那么我们可以思考一下,如果让我们来设计一个Fork/Join框架,该如何设计? 这个思考有助于你理解Fork/Join框架的设计。

第一步分割任务。首先我们需要有一个fork类来把大任务分割成子任务,有可能子任务还是很大,所以还需要不停的分割,直到分割出的子任务足够小。

第二步执行任务并合并结果。分割的子任务分别放在双端队列里,然后几个启动线程分别从双端队列里获取任务执行。子任务执行完的结果都统一放在一个队列里,启动一个线程从队列里拿数据,然后合并这些数据。

Fork/Join使用两个类来完成以上两件事情:

ForkJoinTask:我们要使用ForkJoin框架,必须首先创建一个ForkJoin任务。它提供在任务中执行fork()和join()操作的机制,通常情况下我们不需要直接继承ForkJoinTask类,而只需要继承它的子类,Fork/Join框架提供了以下两个子类: RecursiveAction:用于没有返回结果的任务。 RecursiveTask :用于有返回结果的任务。 ForkJoinPool :ForkJoinTask需要通过ForkJoinPool来执行,任务分割出的子任务会添加到当前工作线程所维护的双端队列中,进入队列的头部。当一个工作线程的队列里暂时没有任务时,它会随机从其他工作线程的队列的尾部获取一个任务。

为什么用的不是很多 由于java7及以前时候,代码比较发杂,java8对stream对Fork-join进行了封装简化 具体的看代码,在运行测试的时候我们打开任务管理器,发现cpu的利用率在运行fork-join时候会很高

java8的并行流和串行流 

 

java1.7

package com.jiuzhouzhi.forkjoin.java7;

import java.util.concurrent.RecursiveTask;

/**
 * @ClassName ForkJoinCaculate
 * @Description java7中Fork/Join框架使用
 * @Author 刘志红
 * @Date 2018/9/12
 **/
public class ForkJoinCaculate extends RecursiveTask {
    private long start;
    private long end;

    /**
     * THRESHOLD 阈值
     */
    private static final long THRESHOLD=10000L;

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

    @Override
    protected Long compute() {
        long sum=0;
        //如果小于等于阈值就计算
        if((end-start)<=THRESHOLD){
            for (long i = start; i <=end ; i++) {
                sum+=i;
            }
        }
        //不然就继续分成小任务
        else{
            long middle=(start+end)/2;
            //如果任务大于阀值,就分裂成两个子任务计算
            ForkJoinCaculate left = new ForkJoinCaculate(start, middle);
            ForkJoinCaculate right = new ForkJoinCaculate(middle + 1, end);
            //执行子任务
            left.fork();
            right.fork();
            //等待子任务执行结束,并得到结果
            long leftResult= (long) left.join();
            long rightResult= (long) right.join();
            sum=leftResult+rightResult;
        }
        return sum;
    }
}
View Code 
package com.jiuzhouzhi.forkjoin.java7;

import org.junit.Test;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

/**
 * @ClassName ForkJoinTest
 * @Description Fork/Join框架测试
 * @Author 刘志红
 * @Date 2018/9/12
 **/
public class ForkJoinTest {
    //使用fork/join方式计算1+2+...+10000000000L 数据小的话用普通的单线程运算快 因为fork-join还需要分任务也是需要耗费时间的 数据量
    //大的话用fork/join运算效率高
    @Test
    public void test() {
        long start = System.currentTimeMillis();  //java7计算时间的方法
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        RecursiveTask recursiveTask = new ForkJoinCaculate(0, 10000L);
        long invoke = (long) forkJoinPool.invoke(recursiveTask);
        System.out.println(invoke);
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }

    //采用普通方式
    @Test
    public void test1() {
        long start = System.currentTimeMillis();
        long sum = 0;
        for (long i = 0; i <= 10000L; i++) {
            sum += i;
        }
        System.out.println(sum);
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }
}
View Code

java1.8

package com.jiuzhouzhi.forkjoin.java8;

import org.junit.Test;

import java.time.Duration;
import java.time.Instant;
import java.util.stream.LongStream;

/**
 * @ClassName ForkJoinTest
 * @Description java8中fork/join的使用
 * @Author 刘志红
 * @Date 2018/9/12
 **/
public class ForkJoinTest {
    @Test
    public void test(){
        Instant start = Instant.now();//java8中计算时间的方法
        long reduce = LongStream.rangeClosed(0, 10000L)
                .parallel()   //不加此句的话是串行流 加上这句是并行流
                .reduce(0, Long::sum);
        System.out.println(reduce);
        Instant end = Instant.now();
        System.out.println(Duration.between(start,end).toMillis());//java8中计算时间的方法
    }
}
View Code

 1)概述

     Stream是Java8的一大亮点,是对容器对象功能的增强,它专注于对容器对象进行各种非常便利、高效的 聚合操作(aggregate operation)或者大批量数据操作。Stream API借助于同样新出现的Lambda表达式,极大的提高编程效率和程序可读性。同时,它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用fork/join并行方式来拆分任务和加速处理过程。所以说,Java8中首次出现的 java.util.stream是一个函数式语言+多核时代综合影响的产物。

 什么是聚合操作

  在传统的J2EE应用中,Java代码经常不得不依赖于关系型数据库的聚合操作来完成诸如:

  • 客户每月平均消费金额
  • 最昂贵的在售商品
  • 本周完成的有效订单(排除了无效的)
  • 取十个数据样本作为首页推荐

这类的操作。但在当今这个数据大爆炸的时代,在数据来源多样化、数据海量化的今天,很多时候不得不脱离 RDBMS,或者以底层返回的数据为基础进行更上层的数据统计。而Java的集合API中,仅仅有极少量的辅助型方法,更多的时候是程序员需要用Iterator来遍历集合,完成相关的聚合应用逻辑,这是一种远不够高效、笨拙的方法。 

 2)用法

Stream 的三个操作步骤

1.创建Stream

     1.可以通过Collection系统集合提供stream()串行流(一个线程)或parallelStream()并行流(多个线程)

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

     3.通过Steam的静态方法of()

     4.创建无限流

public class TestStreamAPI1 {

    @Test
    public void test1(){
        //1.可以通过Collection系统集合提供stream()串行流(一个线程)或parallelStream()并行流(多个线程)
        List<String> list=new ArrayList<>();
        Stream<String> stream1=list.stream();

        //2.通过Arrays中的静态方法stream()获取数组流
        Employee[] emps=new Employee[10];
        Stream<Employee> stream2 = Arrays.stream(emps);

        //3.通过Steam的静态方法of()
        Stream<String> stream3 = Stream.of("aa", "bb", "cc");

        //4.创建无限流
        //迭代
        Stream<Integer> stream4 = Stream.iterate(0, x -> x + 2);
        stream4.limit(10).forEach(System.out::println);
        //生成
        Stream.generate(()->Math.random()).limit(5).forEach(System.out::println);
    }
}
View Code

 

   2.中间操作 :多个中间操作可以连接起来形成一个流水线,除非流水线上出发终止操作,否则中间操作不会执行任何处理而在终止操作时一次性全部处理,成为“惰性求值”

  1. 筛选与切片
filter——接收Lambda, 从流中排除某些元素
limit——截断流,使其元素不超过给定数量
skip(n)——跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补
distinct——筛选,通过流所生成的元素的hashCode()和equals()方法去除重复元素。

2. 映射
     map-映射 接收Lambda 将元素转换成其他形式提取信息。接收一个函数作为参数,该函数会被应用每个元素上,并将其映射成一个新的元素
flagMap-接收一个函数作为参数,将流中每一个值转换成另一个流,然后把所有流连接成一个流
 3. 排序
     sorted()--自然排序 Comparable
sorted(Comparator c) 制定排序 包装类有对应的静态方法 例如Integer.compare() String 有 对象.compareTo()方法
package com.jiuzhouzhi.lambda;

import java.util.Objects;


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

    public Employee() {
    }

    public Employee(String name, Integer age, Double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

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

    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;
    }

    public Employee(String name) {
        this.name = name;
    }

    public Employee(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public enum Status {
        FREE, BUSY, VOCATION;
    }

    @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);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age, salary);
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", salary=" + salary +
                ", status=" + status +
                '}';
    }
}
View Code 
package com.jiuzhouzhi.stream;

import com.jiuzhouzhi.lambda.Employee;
import org.junit.Test;

import java.util.*;
import java.util.stream.Stream;

/**
 * 多个中间操作可以连接起来形成一个流水线,除非流水线上出发终止操作,否则中间操作不会执行任何处理而在终止操作时一次性全部处理,成为“惰性求值”
 */
public class TestStreamAPI2 {
    List<Employee> list = Arrays.asList(
            new Employee("lisi", 25, 4500.0),
            new Employee("zhangsan", 20, 4000.0),
            new Employee("zhangsan", 20, 4000.0),
            new Employee("zhangsan", 20, 4000.0),
            new Employee("wangwu", 35, 6000.0),
            new Employee("zhaoliu", 40, 7000.0)
    );
    List<String> list1 = Arrays.asList("aaa", "bbb", "ccc", "ddd");

    /**
     * 筛选与切片
     * filter——接收Lambda, 从流中排除某些元素
     * limit——截断流,使其元素不超过给定数量
     * skip(n)——跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补
     * distinct——筛选,通过流所生成的元素的hashCode()和equals()方法去除重复元素。
     */
    //1.filter
    @Test
    public void test1() {
        Stream<Employee> employeeStream = list.stream().filter(x -> {
            System.out.println("中间操作不执行");
            return x.getAge() > 25;
        });
        System.out.println("======================");
        //不加下面的终止操作 中间操作的打印语句不执行
        employeeStream.forEach(System.out::println);
        //上面迭代操作是streamAPI自己完成称为内部迭代

        //外部迭代:我们自己写代码迭代

        System.out.println("======================");
        Iterator<Employee> iterator = list.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }

    //limit
    @Test
    public void test2() {

        list.stream().filter(x -> x.getAge() >= 25)
                .limit(2)
                .forEach(System.out::println);
    }

    //skip
    @Test
    public void test3() {
        list.stream().filter(x -> x.getAge() >= 25)
                .skip(2)
                .forEach(System.out::println);
    }

    //distinct 由于distinct是通过流所生成的元素的hashCode()和equals()方法去除重复元素
    //所以使用distinct时候需要重写过滤对象的hashCode和equals方法
    @Test
    public void test4() {
        list.stream().filter(x -> x.getSalary() >= 4000)
                .distinct()
                .forEach(System.out::println);
    }

    /**
     * 映射
     * map-映射 接收Lambda 将元素转换成其他形式提取信息。接收一个函数作为参数,该函数会被应用每个元素上,并将其映射成一个新的元素
     * flagMap-接收一个函数作为参数,将流中每一个值转换成另一个流,然后把所有流连接成一个流
     */
    @Test
    public void test5() {

        list1.stream().map(String::toUpperCase)
                .forEach(System.out::println);
        System.out.println("----------------");
        list.stream().map(Employee::getName).forEach(System.out::println);
        System.out.println("-------------------");
        list1.stream().map(TestStreamAPI2::filterCharacter)
                .forEach(st -> st.forEach(System.out::println));

        System.out.println("---------------------");
        list1.stream().flatMap(TestStreamAPI2::filterCharacter).forEach(System.out::println);

    }

    public static Stream<Character> filterCharacter(String str) {
        List<Character> characters = new ArrayList<>();
        for (Character c : str.toCharArray()
        ) {
            characters.add(c);
        }
        return characters.stream();

    }
    /**
     * 排序
     * sorted()--自然排序 Comparable
     * sorted(Comparator c) 制定排序      包装类有对应的静态方法 例如Integer.compare() String 有 对象.compareTo()方法
     */
    @Test
    public void test7(){
        list1.stream().sorted().forEach(System.out::println);
        list.stream().sorted((x,y)->{
            if (x.getAge().equals(y.getAge())){
                return x.getSalary().compareTo(y.getSalary());
            }
            else{
                return -x.getAge().compareTo(y.getAge());
            }
        }).forEach(System.out::println);
    }
}
View Code
  3.终止操作
1. 查找与匹配 allMatch——检查是否匹配所有元素
anyMatch——检查是否至少匹配一个元素
noneMatch——检查是否没有匹配所有元素
findFirst——返回第一个元素
findAny——返回当前流中的任意元素
count——返回流中元素总个数
max——返回流中元素最大值
min——返回流中元素最小值
2. 规约 reduce(T identity,BignaryOperator) / reduce(BigaryOperator)——可以将流中元素反复结合起来,得到一个值
3. 收集 collect——将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法 collect的参数是Collector接口 java8提供了
Collector操作的工具类Collectors
4.分组
5.分区
package com.jiuzhouzhi.stream;

import com.jiuzhouzhi.lambda.Employee;
import org.junit.Test;

import java.util.*;
import java.util.stream.Collectors;


/**
 * 查找与匹配
 * allMatch——检查是否匹配所有元素
 * anyMatch——检查是否至少匹配一个元素
 * noneMatch——检查是否没有匹配所有元素
 * findFirst——返回第一个元素
 * findAny——返回当前流中的任意元素
 * count——返回流中元素总个数
 * max——返回流中元素最大值
 * min——返回流中元素最小值
 */
public class TestStreamAPI3 {
    List<Employee> list = Arrays.asList(
            new Employee("zhangsan", 20, 4000.0, Employee.Status.FREE),
            new Employee("zhangsan", 20, 4000.0, Employee.Status.BUSY),
            new Employee("zhangsan", 20, 4000.0, Employee.Status.BUSY),
            new Employee("zhangsan", 20, 4000.0, Employee.Status.BUSY),
            new Employee("zhangsan", 20, 4000.0, Employee.Status.BUSY),
            new Employee("wangwu", 35, 6000.0, Employee.Status.BUSY),
            new Employee("wangwu", 35, 6000.0, Employee.Status.BUSY),
            new Employee("zhaoliu", 40, 7000.0, Employee.Status.VOCATION)
    );

    @Test
    public void test1() {
        System.out.println("---------------------allMatch");
        boolean b = list.stream().allMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b);
        System.out.println("---------------anyMatch");
        boolean b1 = list.stream().anyMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b1);
        System.out.println("-------------------noneMatch");
        boolean b2 = list.stream().noneMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b2);
        System.out.println("-----------------findFirst");
        Optional<Employee> first = list.stream().sorted((x, y) -> -Double.compare(x.getSalary(), y.getSalary())).findFirst();
        System.out.println(first.get());
        System.out.println("---------------findAny");
        //由于findAny是找到任何一个元素
        Optional<Employee> any = list.parallelStream().filter(e -> e.getStatus().equals(Employee.Status.BUSY)).findAny();
        System.out.println(any);
    }

    @Test
    public void test2() {
        System.out.println("-----------count");
        long count = list.stream().count();
        System.out.println(count);
        System.out.println("-------------max");
        /*Optional<Employee> max = list.stream().max((x, y) -> Double.compare(x.getSalary(), y.getSalary()));*/
        //用下面的代码等价于上面的
        Optional<Employee> max = list.stream().max(Comparator.comparingDouble(x -> x.getSalary()));
        System.out.println(max.get());
        System.out.println("--------------min");
        Optional<Double> min = list.stream().map(Employee::getSalary).min(Double::compare);
        System.out.println(min.get());
    }
    /**
     * 规约
     * reduce(T identity,BignaryOperator) / reduce(BigaryOperator)——可以将流中元素反复结合起来,得到一个值
     */
    @Test
    public void test3(){
      List<Integer> integers=Arrays.asList(1,2,3,4,5,6,7,8,9);
        Integer reduce = integers.stream().reduce(0, (x, y) -> x + y);
        System.out.println(reduce);
        System.out.println("-----------------------------------------");
        /**
         * map和reduce一起使用称为 map-reduce模式
         */
        Optional<Double> reduce1 = list.stream().map(Employee::getSalary).reduce(Double::sum);
        System.out.println(reduce1.get());

    }
    /**
     * 收集
     * collect——将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
     * collect的参数是Collector接口  java8提供了Collector操作的工具类Collectors
     */
    @Test
    public void test4(){
        System.out.println("--------------------------------------------收集到list中");
        list.stream().map(Employee::getName).collect(Collectors.toList()).forEach(System.out::println);
        System.out.println("---------------------------------------------收集到set中");
        list.stream().map(Employee::getName).collect(Collectors.toSet()).forEach(System.out::println);
        System.out.println("----------------------------------------------收集到hashSet中");
        list.stream().map(Employee::getName).collect(Collectors.toCollection(HashSet::new)).forEach(System.out::println);
    }
    @Test
    public void test5(){
        System.out.println("--------------------------总数");
        Long collect = list.stream().collect(Collectors.counting());
        System.out.println(collect);
        System.out.println("---------------------------平均值");
        Double collect1 = list.stream().collect(Collectors.averagingDouble(Employee::getSalary));
        System.out.println(collect1);
        System.out.println("--------------------------------总和");
        Double collect2 = list.stream().collect(Collectors.summingDouble(Employee::getSalary));
        System.out.println(collect2);
        System.out.println("-------------------------------最大最小值");
        Optional<Double> max1 = list.stream().map(Employee::getSalary).collect(Collectors.maxBy(Double::compare));
        System.out.println(max1.get());
        Optional<Double> min1 = list.stream().map(Employee::getSalary).collect(Collectors.minBy(Double::compare));
        System.out.println(min1.get());
        System.out.println("-------------------------------工资最小值最大值对应的员工");
        Optional<Employee> collect3 = list.stream().collect(Collectors.maxBy((x, y) -> Double.compare(x.getSalary(), y.getSalary())));
        System.out.println(collect3.get());
        Optional<Employee> max = list.stream().max(Comparator.comparingDouble(Employee::getSalary));
        System.out.println(max.get());

    }
    //分组
    @Test
    public void test6(){
        Map<Employee.Status, List<Employee>> collect = list.stream().collect(Collectors.groupingBy(Employee::getStatus));
        System.out.println(collect);
    }
    //多级分组
    @Test
    public void test7(){
        Map<Double, Map<String, List<Employee>>> collect = list.stream().collect(Collectors.groupingBy(Employee::getSalary, Collectors.groupingBy(e -> {
            if (e.getAge() <= 35) {
                return "青年";
            } else return "中年";
        })));
        System.out.println(collect);
    }

    //分区 以及多级分区 和分组类似
    @Test
    public void test8(){
        Map<Boolean, List<Employee>> collect = list.stream().collect(Collectors.partitioningBy(e -> e.getSalary() > 5000));
        System.out.println(collect);
    }
}
View Code

 3) stream和for性能比较

  stream和for性能比较:for本来就是比较底层的操作,性能自然很高。stream的优势是并行处理。数据量越大,stream的优势越明显,数据量小,肯定是for循环性能最好。

 4)总结

总之,Stream 的特性可以归纳为:

  • 不是数据结构;

  • 它没有内部存储,它只是用操作管道从source(数据结构、数组、generator function、IO channel)抓取数据;

  • 它也绝不修改自己所封装的底层数据结构的数据。例如Stream的filter操作会产生一个不包含被过滤元素的新Stream,而不是从source删除那些元素;

  • 所有Stream的操作必须以lambda表达式为参数;

  • 不支持索引访问;

  • 你可以请求第一个元素,但无法请求第二个,第三个,或最后一个;

  • 很容易生成数组或者List;

  • 惰性化;

  • 很多Stream操作是向后延迟的,一直到它弄清楚了最后需要多少数据才会开始;

  • Intermediate操作永远是惰性化的;

  • 并行能力;

  • 当一个 Stream 是并行化的,就不需要再写多线程代码,所有对它的操作会自动并行进行的;

  • 可以是无限的。集合有固定大小,Stream 则不必。limit(n)和findFirst()这类的short-circuiting操作可以对无限的Stream进行运算并很快完成。4

6.新容器类public final class Optional<T>

 java8以前用null代表值不存在,这样会引发空指针异常,为了避免空指针异常java8出来这个类。

package com.jiuzhouzhi.optional;

import org.junit.Test;

import java.lang.management.OperatingSystemMXBean;
import java.util.Optional;

/**
 * @ClassName TestOptional2
 * @Description 举例说明java7以前和java8多了Optional的区别
 * @Author 刘志红
 * @Date 2018/9/12
 **/
public class TestOptional2 {
    /**
     * java7及以前 需要多层if判断null 如果Man Godness中字段更多的话那么需要判断的更多
     */
    public String getGodNessName(Man man) {
        if (man != null) {
            Godness godness = man.getGodness();
            if (godness != null) {
                return godness.getName();
            }
        }
        return "苍老师";
    }

    @Test
    public void test1() {
        Man man = new Man();
        String godNessName = getGodNessName(man);
        System.out.println(godNessName);
    }

    /**
     * java8以后 使用Optional类 NewMan Godness
     */
    public String getGodNessNameNew(Optional<NewMan> man) {
        return man.orElse(new NewMan()).getOptional().orElse(new Godness("苍老师")).getName();
    }

    @Test
    public void test2() {
        Optional<NewMan> o = Optional.ofNullable(null);
        String godNessNameNew = getGodNessNameNew(o);
        System.out.println(godNessNameNew);
        Optional<NewMan> xiaohua = Optional.ofNullable(new NewMan(Optional.ofNullable(new Godness("xiaohua"))));
        String godNessNameNew1 = getGodNessNameNew(xiaohua);
        System.out.println(godNessNameNew1);
    }
}
View Code

常用方法:

package com.jiuzhouzhi.optional;

import com.jiuzhouzhi.lambda.Employee;
import org.junit.Test;

import java.util.Optional;

/**
 * @ClassName TestOptional
 * @Description Optional类的常用方式测试
 * @Author 刘志红
 * @Date 2018/9/12
 **/
public class TestOptional {
    @Test
    public void test1(){
        Optional<Employee> optional = Optional.of(new Employee());
        Employee employee = optional.get();
        System.out.println(employee);
        //创建一个空Optional  打开源码发现ofNullable是 of和empty的综合
        Optional<Object> o = Optional.ofNullable(null);
        System.out.println(o);
        //判断Optional是否有值
        if(o.isPresent()){
            System.out.println(o.get());
        }
        else{
            o=Optional.of(new Employee());
            System.out.println(o);
        }
    }
    @Test
    public void test2(){
        //创建空Optional
        Optional<Object> empty = Optional.empty();
        System.out.println(empty);
        System.out.println(empty.isPresent());
    }
    @Test
    public void test3(){
        // 如果有值返回值 无值用参数代替
        Optional<Object> o = Optional.ofNullable(null);
        Object o1 = o.orElse(new Employee("张三", 25, 10000.0));
        System.out.println(o1);
        Optional<Object> o2 = Optional.ofNullable(new Employee("李四", 25, 10000.0));
        System.out.println(o2);
    }
    @Test
    public void test4(){
        //orElseGet(Supplier s)
        //如果有值返回值 无值返回s获取的值
        //由于参数是函数式接口那么我们可以添加我们想要的功能
        Optional<Object> o = Optional.ofNullable(null);
        Object o1 = o.orElseGet(Employee::new);
        System.out.println(o1);
    }
    @Test
    public void test5(){
        Optional<Employee> optional = Optional.ofNullable(new Employee("张三", 25, 10000.0));
        Optional<String> s = optional.map(Employee::getName);
        System.out.println(s.get());

        Optional<String> s1 = optional.flatMap(e -> Optional.of(e.getName()));
        System.out.println(s1.get());
    }
}
View Code

 7.java8的新时间API

 1) 概述

java8新出的一套时间的API 取代1.0出的Date和1.1的Calendar。Date、Calendar 的格式化存在线程安全问题 。并且时间日期格式化的类 SimpleDateFormat在java.text包中 显的不规范。新出的API都在java.time包下且不存在线程安全问题

测试类:

package com.jiuzhouzhi.time.java7;

import org.junit.Test;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;

/**
 * @ClassName TimeTest
 * @Description java7及之前时间的问题 下面代码存在多线程问题
 * @Author 刘志红
 * @Date 2018/9/12
 **/
public class TimeTest {

    @Test
    public void test1() throws ExecutionException, InterruptedException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
        Callable<Date> task = new Callable<Date>() {
            @Override
            public Date call() throws Exception {
                return simpleDateFormat.parse("20161212");
            }
        };
        //创建十个线程
        ExecutorService pool = Executors.newFixedThreadPool(10);
        List<Future<Date>> list = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            Future<Date> submit = pool.submit(task);//用上面的十个线程执行1000次任务
            list.add(submit);  //执行结果放入list中
        }
        System.out.println(list.size());
        for (int i = 0; i <list.size() ; i++) {
            System.out.println(list.get(i).get());
        }
        pool.shutdown(); //关闭线程池
    }
}
View Code

运行发现出现异常java.util.concurrent.ExecutionException: java.lang.NumberFormatException: For input string: ".1612E.16122E",处理办法 用 synchronized 或者ThreadLocal

添加synchronized比较简单这里不做说明,使用ThreadLocal如下:

package com.jiuzhouzhi.time.java7;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @ClassName DateFormatThreadLocal
 * @Description
 * @Author 刘志红
 * @Date 2018/9/12
 **/
public class DateFormatThreadLocal {
    private static final ThreadLocal<DateFormat> THREAD_LOCAL=new ThreadLocal<DateFormat>(){
        @Override
        protected DateFormat initialValue() {
            return new SimpleDateFormat("yyyyMMdd");
        }
    };
    public static Date converse(String source) throws ParseException {
        return THREAD_LOCAL.get().parse(source);
    }
}


package com.jiuzhouzhi.time.java7;

import org.junit.Test;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;

/**
 * @ClassName TimeTest
 * @Description java7及之前处理时间多线程问题
 * @Author 刘志红
 * @Date 2018/9/12
 **/
public class TimeTestHandled {

    @Test
    public void test1() throws ExecutionException, InterruptedException {
        Callable<Date> task = new Callable<Date>() {
            @Override
            public Date call() throws Exception {
                return com.jiuzhouzhi.time.java7.DateFormatThreadLocal.converse("20161212");
            }
        };
        ExecutorService pool = Executors.newFixedThreadPool(10);
        List<Future<Date>> list = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            Future<Date> submit = pool.submit(task);
            list.add(submit);
        }
        for (Future<Date> f : list
                ) {
            System.out.println(f.get());
        }
        pool.shutdown();
    }
}
View Code 

运行发现没有异常

java8:

package com.jiuzhouzhi.time.java8;

import org.junit.Test;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @ClassName TimeTest
 * @Description java7及之前时间的问题 下面代码存在多线程问题
 * @Author 刘志红
 * @Date 2018/9/12
 **/
public class TimeTestJ8 {

    @Test
    public void test1() throws ExecutionException, InterruptedException {
        DateTimeFormatter dateTimeFormatter=DateTimeFormatter.ofPattern("yyyyMMdd");
        Callable<LocalDate> task = new Callable<LocalDate>() {
            @Override
            public LocalDate call() throws Exception {
                return LocalDate.parse("20161212",dateTimeFormatter);
            }
        };
        ExecutorService pool = Executors.newFixedThreadPool(10);
        List<Future<LocalDate>> list = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            Future<LocalDate> submit = pool.submit(task);
            list.add(submit);
        }
        for (Future<LocalDate> f : list
                ) {
            System.out.println(f.get());
        }
        pool.shutdown();
    }
}
View Code

运行也没有异常

 2)用法

新时间API,LocalDate、LocalTime、LocalDateTime类的实例是不可变的对象。分别表示使用ISO-8601日历系统(国际标准化组织制定的现代公民的日期和时间的表示法)的日期、时间、日期时间。他们提供了简单的日期和时间,并不包含当前的时间信息也不包含与时区相关的信息。

    /**
     * LocalDate  LocalTime  LocalDateTime
     * 这里只举例说明LocalDateTime 其他两个基本差不多 可以查看API
     */
    @Test
    public void test1() {
        LocalDateTime now = LocalDateTime.now();
        System.out.println(now);
        LocalDateTime of = LocalDateTime.of(2018, 10, 21, 12, 0, 20);
        System.out.println(of);
        LocalDateTime localDateTime = now.plusDays(1);
        System.out.println(localDateTime);
        LocalDateTime localDateTime1 = now.minusHours(1);
        System.out.println(localDateTime1);

        System.out.println(now.getYear());
        System.out.println(now.getMonth());
        System.out.println(now.getMonthValue());
        System.out.println(now.getDayOfMonth());
        System.out.println(now.getMonth().getValue());
        System.out.println(now.getDayOfYear());
    }
View Code

时间戳Instant

/**
     * Instant  时间戳(以Unix元年:1970年1月1日00:00:00到某个时间的毫秒值)
     */
    @Test
    public void test2(){
        //获取UTC时区的当前时间
        Instant now1 = Instant.now(); //默认的是UTC时区和中国差8个小时的时差
        System.out.println(now1);

        OffsetDateTime offsetDateTime = now1.atOffset(ZoneOffset.ofHours(8));
        System.out.println(offsetDateTime);
       //转换成毫秒
        System.out.println(now1.toEpochMilli());
       //1970年1月1日00:00:00  为基础获取的时间 第一个是+1000毫秒第二个是+60秒
        Instant instant = Instant.ofEpochMilli(1000);
        Instant instant1 = Instant.ofEpochSecond(60);
        System.out.println(instant);
        System.out.println(instant1);
    }
View Code
/**
     * Duration计算两个时间之间的间隔
     * Period计算两个日期直接的间隔
     */
    @Test
    public void test3(){
        Instant start = Instant.now();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Instant end=Instant.now();
        Duration between = Duration.between(start, end);
        /**
         * 获取对应的需要的时间戳
         * to----方法
         * get---方法
         */
        System.out.println(between.toMillis());
        System.out.println("----------------------");
        LocalTime localTime1=LocalTime.now();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        LocalTime localTime2 = LocalTime.now();
        Duration between1 = Duration.between(localTime1, localTime2);
        System.out.println(between1.toMillis());
    }
    @Test
    public void test4(){
        LocalDate now1 = LocalDate.now();
        LocalDate of = LocalDate.of(2018, 10, 21);
        Period between = Period.between(now1, of);
        System.out.println(between.getYears()+"  "+between.getMonths()+"  "+between.getDays());

    }
View Code

时间矫正器TemporalAdjuester以及工具类TemporalAjuesters:用于操作日期

    /**
     * TemporalAdjuster时间矫正器
     */
    @Test
    public void test5(){
        /**
         * 第一种方式调整时间
         */
        //现在时间
        LocalDateTime now = LocalDateTime.now();
        System.out.println(now);
        //调整日期到本月10号
        LocalDateTime localDateTime = now.withDayOfMonth(10);
        System.out.println(localDateTime);
        System.out.println("-----------------");
        /**
         * 第二种方式调整时间
         */
        //下一个星期日的日期时间
        LocalDateTime with = now.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
        System.out.println(with);

        //自定义  下一个工作日
        //进入TemporalAdjuster我们发现他是一个函数式接口
        //抽象方法  Temporal adjustInto(Temporal temporal);
        LocalDate now1 = LocalDate.now();
        LocalDate with1 = now1.with(x -> {
            DayOfWeek dayOfWeek = now1.getDayOfWeek();
            if (dayOfWeek.equals(DayOfWeek.FRIDAY)) {
                return now1.plusDays(3);
            } else if (dayOfWeek.equals(DayOfWeek.SATURDAY)) {
                return now1.plusDays(2);
            } else {
                return now1.plusDays(1);
            }
        });
        System.out.println("下个工作日"+with1);
    }
View Code

时间格式化 DateTimeFormatter

@Test
    public void test6(){
        /**
         * 使用DateTimeFormat默认提供的格式格式化
         */
        DateTimeFormatter isoLocalDateTime = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
        LocalDateTime localDateTime=LocalDateTime.now();
        String format = isoLocalDateTime.format(localDateTime);
        System.out.println(format);
        System.out.println("----------------");
        /**
         * 自定义的格式
         */
        DateTimeFormatter d = DateTimeFormatter.ofPattern("yyyy年MM月dd日HH小时mm分钟ss秒");
        String format1 = d.format(localDateTime);
        System.out.println(format1);

        /**
         * 上面是显示指定格式的时间 我们也可以把 字符串格式的时间解析回日期时间
         */
        DateTimeFormatter d2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日HH小时mm分钟ss秒");
        LocalDateTime parse = LocalDateTime.parse("2018年09月12日22小时20分钟54秒", d2);
        System.out.println(parse);
    }
View Code

时区的处理:带时区的日期ZonedDate、时间ZonedTime、日期时间ZonedDateTime。其中每个时区都对应着ID。ZoneId类中包含了所有的时区信息。getAvailableZoneIds()可以获取所有时区的信息,of(id)用指定的时区信息获取ZoneId对象

 /**
     * 时区的处理 ZoneDate ZoneTime ZoneDateTime
     * 和LocalDate LocalDateTime LocalTime类似 只不过加上时区
     */
    @Test
    public void test7(){
        //查看所有的时区
    ZoneId.getAvailableZoneIds().forEach(System.out::println);
    }
    @Test
    public void test8(){
        //指定一个时区的当前时间
        LocalDateTime now = LocalDateTime.now(ZoneId.of("America/Los_Angeles"));
        System.out.println(now);
        System.out.println("-----------------");
        //查询当前的ZoneDateTime
        ZonedDateTime now1 = ZonedDateTime.now();
        System.out.println(now1);
        //添加时区
        ZonedDateTime now2 = ZonedDateTime.now(ZoneId.of("America/Los_Angeles"));
        System.out.println(now2);

    }
View Code

 3)和Mysql的对应关系

引用自:https://blog.csdn.net/moxiong3212/article/details/74279739

首先保证数据库驱动不能低于4.2,查看驱动的方法解压jar找到MANIFEST.MF ,在其中找到Specification-Version对应的就是驱动的版本,如果你使用的mysql-connector-java版本低于5.1.37,则数据库的驱动版本低于4.2。运行会报错MysqlDataTruncation: Data truncation: Incorrect date

java时间和数据库时间的对应关系如下:

java                        mysql

LocalDateTime       datetime

LocalDate               date

LocalTime               time

测试:注意数据库驱动jar和数据库版本的对应关系

 test数据库中创建表:create table tb_java8date (id int not null primary key auto_increment,t_date date, t_time time, t_datetime datetime);

 @Test
    public void test9() throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/test?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC","root","1234");
        PreparedStatement st = conn.prepareStatement("insert into tb_java8date (t_date,t_time,t_datetime)values(?,?,?)");
        st.setObject(1, LocalDate.now());
        st.setObject(2, LocalTime.now());
        st.setObject(3, LocalDateTime.now());
        st.execute();
        st.close();
        conn.close();
    }
View Code

运行刷新数据库发现添加成功

8.对注解的改进

1)添加元注解@Repeatable

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {
    /**
     * Indicates the <em>containing annotation type</em> for the
     * repeatable annotation type.
     * @return the containing annotation type
     */
    Class<? extends Annotation> value();
}

2)@Target中添加了两种作用类型
/**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE

 

转载于:https://www.cnblogs.com/chengxuyuan-liu/p/10590216.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值