6.java8新特性

java8新特性

Java8对内存结构进行了优化,同时对HashMap的底层结构进行了优化,从原来的数字加链表的结构改变为数组加红黑树的结构提升了效率

  1. lambda表达式
  2. stream串行流和并行流
  3. Java8中新的时间API Instant LocalTime LocalDateTime
一:lambda表达式

lambda表达式是一个匿名函数,我们可以把它理解为是一段可传递的代码(将代码向数据一样进行传递)。可以写更简洁的代码,作为一种更简洁的代码使Java的语言表达能力得到了提升。

案例一:lambda表达式初体验一
//匿名内部类的写法
/**
 * TreeSet构造时要传入一个比较器
 * 	你可以将其修改为一个实现了Comparator接口的子类
 * @author Administrator
 *
 */
public class TestLambda {
	//匿名内部类的写法
	@Test
	public void test01() {
		Comparator<Integer> com = new Comparator<Integer>() {
			@Override
			public int compare(Integer o1, Integer o2) {
				return Integer.compare(o1,o2);
			}			
		};
		
		TreeSet<Integer> set = new TreeSet<Integer>(com);
		int compare = com.compare(1, 3);
		System.out.println(compare);
	}
	
	//lambda表达式的写法
	@Test
	public void test02() {
		Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
		TreeSet<Integer> set = new TreeSet<Integer>(com);
		int compare = com.compare(3,1);//x<y返回-1 反之返货1
		System.out.println(compare);		
	}	
}	
案例二:lambda表达式初体验二
	List<Employee>	emps = Arrays.asList(
			new Employee("张三", 33, 3333.33),
			new Employee("李四", 44, 4444.44),
			new Employee("王五", 55, 5555.55),
			new Employee("赵六", 66, 6666.66),
			new Employee("田七", 22, 2222.22)
			);
	
	/**
	 * 	传统的写法
	 *	  
	 */
	@Test
	public void TestOriginal() {
		System.out.println("===按年龄查询========");
		List<Employee> selectByAge = selectByAge(emps);
		for (Employee employee : selectByAge) {
			System.out.println(employee);
		}
		System.out.println("===按工资查询========");		
		List<Employee> selectBySalary = selectBySalary(emps);
		for (Employee employee : selectBySalary) {
			System.out.println(employee);
		}
	}
	//查询年龄大于35的
	public List<Employee> selectByAge(List<Employee> emps){
		List<Employee> emp1 = new ArrayList<Employee>();		
		for (Employee employee : emps) {
			if(employee.getAge()>35) {
				emp1.add(employee);
			}
		}
		return emp1;
	}
	
	//查询年龄大于35的
		public List<Employee> selectBySalary(List<Employee> emps){
			List<Employee> emp1 = new ArrayList<Employee>();			
			for (Employee employee : emps) {
				if(employee.getSalary()>5000) {
					emp1.add(employee);
				}
			}
			return emp1;
		}

/**
		 * 	优化方式一:
		 * 	使用设计模式的写法《程序的开闭原则》
		 * 	1:定义一个接口interface MyCompare<T>
		 * 	2:增加一个按年龄比较的实现类SelectByAge implements MyCompare<Employee>
		 * 	3:增加一个工资比较的实现类SelectBySalary implements MyCompare<Employee>
		 */
		@Test
		public void test03() {
			System.out.println("===按年龄查询========");
			List<Employee> SelectByAge = selectByCon(emps,new SelectByAge());
			for (Employee employee : SelectByAge) {
				System.out.println(employee);
			}
			System.out.println("===按工资查询========");		
			List<Employee> selectBySalary = selectByCon(emps,new SelectBySalary());
			for (Employee employee : selectBySalary) {
				System.out.println(employee);
			}
		}
        //定义接口
        public interface MyCompare<T> {	
            public boolean compare(T t);
        }
		//增加实现类
		public class SelectByAge implements MyCompare<Employee>{
            @Override
            public boolean compare(Employee emp) {
                if(emp.getAge()>35) {
                    return true;
                }
                return false;		
            }
        }
		//增加实现类
		public class SelectBySalary implements MyCompare<Employee>{
        @Override
        public boolean compare(Employee emp) {
                if(emp.getSalary()>5000) {
                    return true;
                }
                return false;		
            }
        }
		//通用方法
		public List<Employee> selectByCon(List<Employee> srcList,MyCompare<Employee> compare){
			ArrayList<Employee> destList = new ArrayList<Employee>();
			for (Employee employee : srcList) {
				if(compare.compare(employee)) {
					destList.add(employee);
				}
			}
			return destList;
		}

案例二:优化的方式二,三

/**
	 * 优化的方式二使用匿名内部类
	 * 仍然要配合上面的通用方法
	 */
	public List<Employee> selectByCon(List<Employee> srcList,MyCompare<Employee> compare){
		ArrayList<Employee> destList = new ArrayList<Employee>();
		for (Employee employee : srcList) {
			if(compare.compare(employee)) {
				destList.add(employee);
			}
		}
		return destList;
	}
	@Test
	public void test3() {
		List<Employee> selectByAge = selectByCon(emps,new MyCompare<Employee>() {
			@Override
			public boolean compare(Employee t) {
				return t.getAge()>35;
			}
		});
		for (Employee employee : selectByAge) {
			System.out.println(employee);
		}
		System.out.println("====安工资过滤=======");
		List<Employee> selectBySalary = selectByCon(emps,new MyCompare<Employee>() {
			@Override
			public boolean compare(Employee t) {
				return t.getSalary()>=5000;
			}
		});
		for (Employee employee : selectBySalary) {
			System.out.println(employee);
		}
	}
	/** 
	 * 优化方式三还要借助上面定义的接口和通用方法
	 * 使用lambda表达式
	 */
	@Test
	public void test3() {
		List<Employee> selectByAge = selectByCon(emps,(e)-> e.getAge()>35);
		selectByAge.forEach(System.out::println);
	}

案例二:之优化四不需要上面任何的接口和通用方法

	/** 
	 * 优化方式四
	 * 使用lambda表达式
	 */
	@Test
	public void test4() {
		emps.stream()
			.filter((e)->e.getAge()>35)
			.forEach(System.out::println);
	}
二:sream API初体验
@Test
	public void test4() {
		emps.stream()
			.filter((e)->e.getAge()>35)
			.forEach(System.out::println);
		//只取前两个
		emps.stream()
		.filter((e)->e.getAge()>35)
		.limit(2)
		.forEach(System.out::println);
		
		//取出集合中所有人的名字
		emps.stream()
		.map((e)->e.getName())
		.forEach(System.out::println);
	}
三:Lambda表达式的语法
  1. 在Java8中引入了一个新的操作符 “->” 该箭头称之为箭头操作符或Lambda操作符,箭头操作符将Lambda表达式分为左右两部分

    1. 左侧:是lambda表达式的参数列表(是所需的函数式接口中的参数列表)
    2. 右侧:是lambda表达式所需执行的功能 即lambda体(即使对函数式接口中抽象方法的实现)
  2. lambda的使用需要有函数式接口的支持(即接口中只能有一个抽象方法的接口),函数式接口可以使用@FunctionalInterface注解修饰,会自动帮我们检查是否属于函数式接口(即是否只有一个抽象方法)

  3. 语法格式

    1. 无参 无返回值

      	@Test
      	public void test5() {
      		Runnable runnable = new Runnable() {
      			@Override
      			public void run() {
      				System.out.println("hello wold");
      			}
      		};
      		runnable.run();
      		System.out.println("=========lambda=======");
      		Runnable runnable1 = () ->System.out.println("hello lambda");
      		runnable1.run();
      	}
      
    2. 有一个参数 无返回值 (若只有一个参数小括号可以不写)

      	@Test
      	public void test6() {
      			Consumer<String> c = (x) -> System.out.println(x);
      			c.accept("有一个参数 且无返回值");
      	}
      	@Test
      	public void test6() {
      			Consumer<String> c = x -> System.out.println(x);
      			c.accept("有一个参数 且无返回值");
      	}
      
    3. 有多个参数 并且有返回值 并且lambda体中有多条语句(如果只有一条语句大括号和return都可以省略)

      	@Test
      	public void test7() {
      		Comparator<Integer> com = (x,y) ->{
      			System.out.println("有多个参数并且有返回值!!");
      			return Integer.compare(x, y);
      		};
      		com.compare(1, 3);
      	}
      	/**
      	 * 如果只有一条语句大括号和return都可以省略
      	 */
      	@Test
      	public void test7() {
      		Comparator<Integer> com = (x,y) ->Integer.compare(x, y);	
      	}
      
    4. lambda表达式的参数列表的参数类型可以省略不写,因为JVM编译器通过上下文推断出数据类型,即类型推断Comparator com = (Integer x,Integer y) ->Integer.compare(x, y)

      	@Test
      	public void test7() {
      		Comparator<Integer> com = (x,y) ->Integer.compare(x, y);	
      		//之前我们使用过的类型推断例如数组
      		String [] strs = {"aaa","bbbb","cccc"};
      		//但是如果分开来写就会报错
      //		String [] strs1;
      //		strs1 = {"aaa","bbbb","cccc"};
      		//在jdk 1.7中
      		List<Integer> list = new ArrayList<>();
      		//只有在JDK 1.8中才能实现的
      		show(new HashMap<>());
       	}
      	
      	public void show(Map<String,Object> map) {		
      	}
      
    5. lambda的应用

      @FunctionalInterface
      public interface MyFun<T> {
      	public T getValue(T t);
      }
      
      //对一个数字进行运算
      @Test()
      public void test8() {
        Integer opration = opration(100,(x) -> x * x);
        System.out.println(opration);
      
        Integer opration1 = opration(100,(x) -> x +200);
        System.out.println(opration1);
      }
      
      public Integer opration(Integer num,MyFun<Integer> fun) {
        return fun.getValue(num);
      }
      

      练习题1:Collection.sort()方法通过定制排序Employee(先按年龄比,年龄相同再按姓名比)使用lambda表达式

      	@Test
      	public void test9() {
      		Collections.sort(emps, (x,y)->{
      			if(x.getAge()==y.getAge()) {
      				return x.getName().compareTo(y.getName());
      			}else {
      				return  Integer.compare(x.getAge(), y.getAge());
      			}
      		}); 
      		
      		for (Employee employee : emps) {
      			System.out.println(employee);
      		}
      	}
      

      练习题2:①声明函数式接口,接口中声明抽象方法public String getValue(String str);

      ​ ②声明类TestLambda1,类中编写方法使用接口操作参数,将一个字符串转换为大写,并作为方法的返回值

      ​ ③再将一个字符串的第2个到第四个索引位置进行截取

      @FunctionalInterface
      public interface MyStrFun {
      	public String getValue(String str);
      }
      
      public String changStr(String str,MyStrFun myFun) {
      		return myFun.getValue(str);
      	}
      
      @Test
      public void test10() {
        //去除收尾空格
        String changStr = changStr("      加中实训           ",(str) ->str.trim());
        System.out.println(changStr);
        //将字母转为大写
        String upper = changStr("abcdef",(str) ->str.toUpperCase());
        System.out.println(upper);
      
        //将字母转为大写
        String substr = changStr("西安加中实训品牌",(str) ->str.substring(2, 6));
        System.out.println(substr);
      
      }
      

      练习三:声明一个带两个泛型的函数式接口泛型类型为 <T,R> T为传入参数 R为返回值,接口中声明对应的方法

      ①使用接口作为参数,计算两个long类型的和

      ②在计算两个long类型的乘积

      @FunctionalInterface
      public interface MyFun2<T,R> {
      	public R getValue(T t1,T t2);
      }
      
      public void op(Long t1,Long t2,MyFun2<Long,Long> myFun) {
        System.out.println(myFun.getValue(t1,t2));
      }
      
      @Test
      public void test11() {
        //计算两个long类型的和
        op(200L,100L,(x,y)->x + y);
        //计算两个long类型的乘积
        op(200L,100L,(x,y)->x * y);
      }
      
      四:Java8中的四大核心函数式接口,除了这几种以外他们都还有自己的子类扩展接口可以供我们使用
      @FunctionalInterface
      public interface Consumer<T>  //消费型接口
      			void accept(T t);
      
      @FunctionalInterface		  //供给形接口
      public interface Supplier<T>
      				T get();
      
      @FunctionalInterface		//函数型接口
      public interface Function<T, R>
        				 R apply(T t);
       @FunctionalInterface
      public interface Predicate<T>//断言型接口
      			  boolean test(T t);
      

      四大接口的应用

      /**
      	 * 测试消费型接口
      	 * Consumer<T>
      	 * 消费型接口是没有返回值的
      	 */
      	@Test
      	public void testConsumer() {
      		consumer(100d,(m) ->System.out.println("每周乘高铁消费"+m));
      	}
      	
      	public void consumer(Double money,Consumer<Double> con) {
      		con.accept(money);
      	}
      	
      	/**
      	 * 测试供给形接口
      	 * Supplier<T>
      	 * 就是有返回值用来产生对象的
      	 */
      	@Test
      	public void testSupplier() {
      		List<Integer> proList = pro(10,()->(int)(Math.random()*100));
      		System.out.println(proList);
      	}
      	//产生指定的整数,并放入集合中
      	public List<Integer> pro(int num,Supplier<Integer> sup){
      		List<Integer> list = new ArrayList<Integer>();
      		for (int i = 0; i < num; i++) {
      			Integer integer = sup.get();//整数由该方法的实现产生
      			list.add(integer);
      		}
      		return list;
      	}
      	
      	/**
      	 * 函数式接口
      	 * Function<T, R>
      	 * 假设需求:处理字符串等因为他是有输入和输出参数的
      	 */
      	@Test
      	public void testFunction() {
      		String strHandler = strHandler("abcd",(str)->str.toUpperCase());
      		System.out.println(strHandler);
      	}
      	public String strHandler(String str,Function<String, String> fun) {
      		return fun.apply(str);
      	}
      	
      	/**
      	 * 断言型接口
      	 * Predicate<T>
      	 */
      	@Test
      	public void test4() {
      		List<String> list = Arrays.asList("aba","bbb","ccc");
      		List<String> filterStr = filterStr(list,(e)->e.contains("b"));
      		System.out.println(filterStr);
      	}
      	public List<String> filterStr(List<String> strList,Predicate<String> pre){
      		List<String> arrayList = new ArrayList<String>();
      		for (String string : strList) {
      			if(pre.test(string)) {//怎样的判断,怎在lambda表达式中体现
      				arrayList.add(string);
      			}
      		}
      		return arrayList;
      	}
      
四:方法引用和构造器引用,数组引用
1.方法引用
  1. 概念:若Lambda体中的内容有方已经实现了,我们可以使用方法引用

    (可以理解为方法引用是Lambda表达式的另一种表现形式)

  2. 主要有三种语法结构

    对象::实例方法名

    类::静态方法名

    类::实例方法名

    1. 对象名::实例方法名
     * 使用方法引用的注意事项:
    	 * 1:要实现的方法是Comsumer中的accept(T t)的参数列表个数和类型要和
    	 * println()的参数列表的个数和类型要一致
    	 * 2:返回值的类型也要一致
    
    /**
    	 * 对象名::实例方法名
    	 */
    	@Test
    	public void test01() {
    		Consumer<String> com = (x)->System.out.println(x);
    		com.accept("aaa");
    		/**
    		 * println()是System.out对象的实例方法(已经实现了)
    		 * 使用方法引用的注意事项:
    		 * 1:要实现的方法是Comsumer中的accept(T t)的参数列表个数和类型要和
    		 * println()的参数列表的个数和类型要一致
    		 * 2:返回值的类型也要一致
    		 * 因此上边的写法可以改造为如下
    		 */
    		Consumer<String> com1 = System.out::println;
    		com1.accept("aaa");
    	}
    	@Test
    	public void test02() {
    		Employee emp = new Employee("张收纳", 12, 44.44);
    		Supplier<String> sup = ()->emp.getName();
    		String name = sup.get();
    		System.out.println(name);
    		/**
    		 * 使用方法引用可以修改为
    		 */
    		Supplier<String> sup1 = emp::getName;
    		String name1 = sup1.get();
    		System.out.println(name1);
    	}
    
    1. 类名::静态方法名
    	/**
    	 * 类::静态方法名
    	 */
    	@Test
    	public void test03() {
    		Comparator<Integer> com = (x,y)->Integer.compare(x, y);
    		int compare = com.compare(1, 2);
    		System.out.println(compare);
    		//使用静态方法引用和方法引用的规则是相同的
    		Comparator<Integer> com1 = Integer::compare;
    		int compare1 = com1.compare(1, 2);
    		System.out.println(compare1);
    	}
    
    1. 类名::实例方法名
     * 使用的注意事项:
     * 参数列表中的第一个参数是实例方法的调用者,第二个参数是实例方法的参数时
     * 我们就可以使用类名::实例方法名
    
    /**
    	 * 类::实例方法名
    	 * 案例:比较两个字符串是否相等
    	 * 使用的注意事项:
    	 * 参数列表中的第一个参数是实例方法的调用者,第二个参数是实例方法的参数时
    	 * 我们就可以使用类名::实例方法名
    	 */
    	@Test
    	public void test04() {
    		BiPredicate<String, String> bp = (x,y)->x.equals(y);
    		System.out.println(bp.test("a", "b"));
    		//使用  类名::实例方法名的代码改造为
    		BiPredicate<String, String> bp1 = String::equals;
    		System.out.println(bp1.test("a", "b"));	
    	}
    
2.构造器引用
  1. 语法格式:ClassName::new (构造方法要和接口中抽象方法的参数列表保持一致)
/**
	 * 构造器引用
	 * ClassName::new
	 */
	@Test
	public void test05() {
		Supplier<Employee> sup = ()->new Employee();
		Employee employee = sup.get();
		System.out.println(employee);
		//使用构造器引用
		Supplier<Employee> sup1 = Employee::new;
		Employee employee1 = sup.get();
		System.out.println(employee1);
	}
	
	/**
	 * 构造器引用
	 * ClassName::new
	 * 构造方法要和接口中抽象方法的参数列表保持一致
	 */
	@Test
	public void test06() {
		Function<String, Employee> fun = (x)->new Employee(x);
		Employee apply = fun.apply("张三");
		System.out.println(apply);
		//使用构造器引用
		Function<String, Employee> fun1 = Employee::new;
		Employee apply1 = fun.apply("张三");
		System.out.println(apply1);
	}
3.数组引用
/**
	 * 数组引用
	 * Type::new
	 * 
	 */
	@Test
	public void test07() {
		Function<Integer, String[]> fun = (x)->new String[x];
		String[] strs= fun.apply(5);
		System.out.println(strs.length);
		//使用构造器引用
		Function<Integer, String[]> fun1 = String[]::new;
		String[] strs1= fun1.apply(5);
		System.out.println(strs1.length);
	}
五:强大的stream API

stream是Java8中处理集合的关键抽象概念,他可以指定你希望对集合的操作,可以执行非常复杂的查找,过滤和映射数据等操作。使用stream操作集合就类似于sql执行的对数据库查询,也可以使用stream来执行并行的操作提高性能,简而言之,Stream API提供了一种高效处理数据的方式。

流到底是什么?
是数据的渠道,用于操作数据源(集合,数组等)所生成的元素序列
“集合讲得是数据的存储,流讲得是数据的计算”
注意:
1:stream自己不会存储数据
2:stream不会改变源对象,想反他会返回一个持有新结果的流
3:stream操作是延迟执行的,因此他要等到需要结果的时候才执行

stream操作的三个步骤
1:创建stream
一个数据源(集合,数组)获取一个流
2:中间操作
一个中间的操作链,对流进行一系列的相关操作(过滤,映射等)
3:终止操作
一个终止操作,才会执行中间的操作链,并返回一个结果
一:创建流的四种方式
/**
 * stream API的使用
 * @author Administrator
 *	创建stream的四种方式
 *	1:使用collection类型的提供的
 *  ①stream()方法可以创建一个串行流
 *  ②parallelStream()创建一个并行流
 *  
 *  2.通过Arrays中的stream()可以产生一个数组流
 *  
 *  3.通过Stream类中的静态方法
 *  
 *  4:创建无限流
 */
public class TestStream1 {
	List<Employee>	emps = Arrays.asList(
			new Employee("张三", 33, 3333.33),
			new Employee("李四", 44, 4444.44),
			new Employee("王五", 55, 5555.55),
			new Employee("赵六", 66, 6666.66),
			new Employee("田七", 22, 2222.22)
			);
	
	@Test
	public void testCreateStream() {
		//1:使用collection类型的提供的
		Stream<Employee> stream = emps.stream();//stream()
		Stream<Employee> parallelStream = emps.parallelStream();
		
		//2.通过Arrays中的stream()可以产生一个数组流
		Employee [] empArr = new Employee[10];
		Stream<Employee> stream2 = Arrays.stream(empArr);
		
		//3.通过Stream类中的静态方法
		Stream<String> of = Stream.of("aa","bb","cc");
		
		//4:创建无限流
		/**
		 * 迭代       第二个参数类型是
		 * @author Administrator
		 * @FunctionalInterface
		 * public interface UnaryOperator<T> extends Function<T, T>
		 */		
		Stream<Integer> iterate = Stream.iterate(0, (x)->x+2);
		iterate.limit(10).forEach(System.out::println);
		
		/**
		 * 生成
		 */
		Stream<Double> iterate2 = Stream.generate(Math::random);
		iterate2.limit(10).forEach(System.out::println);
	}	
}
二:stream的中间操作
多个中间操作连接起来可以形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理
而在终止操作执行时一次性执行,称之为惰性求值
  1. 刷选或切片
方法名描述
filter(Predicate p)接收Lambda,从流中排除某些元素
distinct()筛选通过流所生成的hashcod和equals方法去除重发
limit(long maxSize)截断流使其元素不超过给定的数量
skip(long n)跳过元素返回一个扔掉前面n个元素的流,若流中元素不足n个则返回一个空流,与limit互补
package com;

import java.util.Arrays;
import java.util.List;

import org.junit.Test;

/**
 * 中间操作
 * @author Administrator
 *
 */
public class TestStream2 {
	List<Employee>	emps = Arrays.asList(
			new Employee("张三", 33, 3333.33),
			new Employee("李四", 44, 4444.44),
			new Employee("王五", 55, 5555.55),
			new Employee("赵六", 66, 6666.66),
			new Employee("田七", 22, 2222.22),
			new Employee("田七", 22, 2222.22),
			new Employee("田七", 22, 2222.22),
			new Employee("田七", 22, 2222.22)
			);
	/**
	 * 过滤filter(Predicate p)
	 */
	@Test
	public void test01() {
		emps.stream()
			.filter((x)->x.getAge()>35)
			.forEach(System.out::println);

		emps.stream()
		.filter((x)->{
			System.out.println("stream api 的中间操作");
			return x.getAge()>35;
		})
		.forEach(System.out::println);
	}	
	/**
	 * 截断limit(long maxSzie)
	 */
	@Test
	public void test02() {
		emps.stream()
		.filter((x)->{
			System.out.println("短路!!!");
			return x.getAge()>35;
		}).limit(2)
		.forEach(System.out::println);
	}	
	/**
	 * distinct()去重
	 * 要想使用:必须得重写对象的hashcode和equeals方法
	 */
	@Test
	public void test03() {
		emps.stream()
		.distinct()
		.forEach(System.out::println);
	}
}
  1. 映射
方法名描述
map(Function f)
mapToDouble(ToDoubleFunction f)接受一个函数作为参数,将函数应用到每个元素上差生一个新的元素
mapToInt(ToIntFunction f)接受一个函数作为参数,将函数应用到每个元素上差生一个新的IntStream
mapToLong(ToLongFunction f)接受一个函数作为参数,将函数应用到每个元素上差生一个新的LongStream
flatMap(Function f)接受一个函数作为参数,将流中的每一个值都换成一个流,然后把所有的流合并成一个流
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
import org.junit.Test;

/**
 * map()接受一个lambda表达式,将元素转化为其他形式或提取信息,
 * 接收一个函数作为参数,该函数应用到每个元素上,并将其映射为一个新的元素
 * flatMap--接收一个函数作为参数,将流中的每一个元素转换为另一个流,然后将每个流合并成一个流
 * @author Administrator
 *
 */
public class TestStream3 {
	List<String> list = Arrays.asList("aaa","bbb","cccc");
	@Test
	public void test01() {
		list.stream()
		.map((e)->e.toUpperCase())
		.forEach(System.out::println);
		
		/**
		 * 对比map和flatMap的区别?
		 * 如下的例子:是使用map的结构进行的拆分
		 */
		System.out.println("-===============map拆分字符串====================");
		Stream<Stream<Character>> map = list.stream()//{{a,a,a},{b,b,b},{c.c.c}}
			                                .map(TestStream3::filter);
		map.forEach((sm)->{
			sm.forEach(System.out::println);
		});
		/**
		 * 使用flatMap对字符进行拆分
		 * @param str
		 * @return
		 */
		System.out.println("===========flatMap拆分字符串==============");
		Stream<Character> flatMap = list.stream()
			.flatMap(TestStream3::filter);//{a,a,a,b,b,b,c,c,c}
		/**
		 * 综合上面的两个案例我们
		 * 得出的结论是map是将每一个元素拆分成了一个原单位的流的对象再放入流中
		 * 而flatMap是将每一个元素拆分成了一个个单独的字符节点流,然后又将所有的节点流
		 * 合并成了一个完整的整体
		 */
		flatMap.forEach(System.out::println); 
	}
	
	//拆分字符串
	public static Stream<Character> filter(String str){
		List<Character> list = new ArrayList<Character>();
		for(Character ch:str.toCharArray()) {
			list.add(ch);
		}
		return list.stream();
	}

	@SuppressWarnings("rawtypes")
	@Test
	public void test02() {
		List<String> list = Arrays.asList("MM","NN","SS");
		List list2 = new ArrayList();
		list2.add(11);
		list2.add(22);
		list2.add(list);
		/**
		 * 在这里观察list.add(Object obj)和list.addAll(Colletion<T> c)的区别
		 * add()执行的效果:[11, 22, [MM, NN, SS]]
		 * addAll()执行的效果:[11, 22, MM, NN, SS]
		 */
		System.out.println(list2);
		list2.addAll(list);
		System.out.println(list2);
	}
}
  1. 排序
方法名描述
sorted()产生一个新的流,按自然书序排序
sorted(Comparetor comp)产生一个新的流,按比较器定义进行排序,也称自定义排序
import java.util.Arrays;
import java.util.List;
import org.junit.Test;

/**
 * sorted()自然排序(就是按字典序或自然顺序Comparable)
 * 定制排序sorted(Comparator com)
 */
public class TestStream4 {
	List<Employee>	emps = Arrays.asList(
			new Employee("张三", 33, 3333.33),
			new Employee("李四", 44, 4444.44),
			new Employee("王五", 55, 5555.55),
			new Employee("赵六", 66, 6666.66),
			new Employee("田七", 22, 2222.22)
			);
	@Test
	public void test01() {
		System.out.println("======自然排序==============");
		List<String> list = Arrays.asList("eee","fff","aaa","bbb","cccc");
		list.stream()
			.sorted()
			.forEach(System.out::println);
		System.out.println("======定制排序==============");
		emps.stream()
			.sorted((e1,e2)->{
				if(e1.getName().equals(e2.getName())) {
					return e1.getAge().compareTo(e2.getAge());
				}else {
					return e1.getAge().compareTo(e2.getAge());
				}
			}).forEach(System.out::println);
	}
}
三:stream的终止操作
方法名描述
allMatch(Predicate p)检查是否匹配全部元素
anyMatch(Predicate p)检查至少匹配一个元素
noneMatch(Predicate p)检查是否没有匹配所有的元素
findFirst()返回第一个元素
findAny()返回当前流中的任意元素
count()返回流中元素的总个数
max()返回流中的最大值
min()返回流中的最小值
reduce(T indentity,BinaryOperate)归约将流中的元素反复结合运算,得到一个值
collect将流转化为其它形式,接收一个Collector接口的实现
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import org.junit.Test;

/**
 * 终止操作
 * 1:查找与匹配
 * 2:归约reduce(T indentity,BinaryOperate)
 * reduce(BinaryOperate)两个都可以将流中的元素反复结合运算,得到一个值
 */
public class TestStream5 {
	List<Employee>	emps = Arrays.asList(
			new Employee("张三", 33, 3333.33,Status.FREE),
			new Employee("李四", 44, 4444.44,Status.BUSY),
			new Employee("王五", 55, 5555.55,Status.BUSY),
			new Employee("赵六", 66, 6666.66,Status.VOCATION),
			new Employee("田七", 22, 2222.22,Status.FREE)
			);
	/**
	 * 检查是否匹配所有的元素
	 * allMatch(Predicate p) 
	 */
	@Test
	public void test01() {
		boolean allMatch = emps.stream()
				.allMatch((x)->x.getStatus().equals(Status.BUSY));
		System.out.println("检查是否匹配所有的元素"+allMatch);

		boolean anyMatch = emps.stream()
				.anyMatch((x)->x.getStatus().equals(Status.BUSY));
		System.out.println("检查至少一个匹配"+anyMatch);

		boolean noneMatch = emps.stream()
				.noneMatch((x)->x.getStatus().equals(Status.BUSY));
		System.out.println("检查是否没有元素匹配到"+noneMatch);

		Optional<Employee> findFirst = emps.stream()
				.sorted((e1,e2)->Double.compare(e1.getSalary(),e2.getSalary()))
				.findFirst();
		System.out.println("返回第一个元素,"
				+ "并将第一个可能为空的元素封装到Optional容器中"+findFirst.get());

	}

	@Test
	public void test02() {
		Optional<Employee> findAny = emps.parallelStream()//这里使用的是并行流
				.filter((e)->e.getStatus().equals(Status.FREE))
				.findAny();
		System.out.println("返回任意一个元素,"
				+ "并将第一个可能为空的元素封装到Optional容器中"+findAny.get());

		Optional<Double> min = emps.stream()//这里使用的是并行流
				.map(Employee::getSalary)
				.min(Double::compare);
		System.out.println("返回公司中最低工资是多少,"
				+ "并将第一个可能为空的元素封装到Optional容器中"+min.get());
	}
	/**
	 * 2:归约reduce(T indentity,BinaryOperate)
	 * reduce(BinaryOperate)两个都可以将流中的元素反复结合运算,得到一个值
	 */
	@Test
	public void test03() {
		List<Integer> asList = Arrays.asList(1,2,3,4,5,6,7,8,9);

		Integer reduce = asList.stream()
				.reduce(0,(x,y)->x+y);//因为这种方法是有起始值的所以不可能为空
		System.out.println(reduce);

		//计算公司中工资的总和
		Optional<Double> reduce2 = emps.stream()
				.map(Employee::getSalary)//没有起始值所以有可能为空
				.reduce(Double::sum);
		System.out.println("公司中工资的总和:"+reduce2.get());
	}

	/**
	 * collect将流转换为其它形式,接收一个Collector接口的实现
	 * Collector中方法的实现决定了如何对流执行收集操作(如收集到List Set Map)
	 * 但是Collectors实用类中提供了很多的静态方法,可以方便的创建常见的的收集器实例
	 * 案例一:将emps中的员工姓名收集到集合中
	 */
	@Test
	public void testCollect1() {
		List<String> list = emps.stream()
				.map(Employee::getName)//拿到所有员工的名字
				.collect(Collectors.toList());
		list.forEach(System.out::println);
		System.out.println("======================================");
		Set<String> set = emps.stream()
				.map(Employee::getName)//拿到所有员工的名字
				.collect(Collectors.toSet());
		set.forEach(System.out::println);

		System.out.println("================收集到特殊的集合HashSet中======================");
		HashSet<String> HashSet = emps.stream()
				.map(Employee::getName)//拿到所有员工的名字
				.collect(Collectors.toCollection(HashSet::new));
		HashSet.forEach(System.out::println);
		System.out.println("================收集到特殊的集合LinkedList中======================");
		LinkedList<String> linkedList = emps.stream()
				.map(Employee::getName)//拿到所有员工的名字
				.collect(Collectors.toCollection(LinkedList::new));
		linkedList.forEach(System.out::println);
	}

	@Test
	public void testCollect2() {
		//计算集合中员工总数
		Long collect = emps.stream()
				.collect(Collectors.counting());
		System.out.println(collect);
		//计算工资的平均值
		Double avg = emps.stream()
				.collect(Collectors.averagingDouble(Employee::getSalary));
		System.out.println("工资的平均值:"+avg);

		//计算工资的总和
		Double sum = emps.stream()
				.collect(Collectors.summingDouble(Employee::getSalary));
		System.out.println("工资的总和:"+sum);
		//最大值
		Optional<Employee> maxSalary = emps.stream()
				.collect(Collectors.maxBy((e1,e2)->Double.compare(e1.getSalary(), e2.getSalary())));
		System.out.println("最高工资的员工信息:"+maxSalary.get());
		//最小值
		Optional<Employee> minSalary = emps.stream()
				.collect(Collectors.minBy((e1,e2)->Double.compare(e1.getSalary(), e2.getSalary())));
		System.out.println("最低工资的员工信息:"+minSalary.get());
	}
	/**
	 * 类似sql的group by 操作
	 */
	@Test
	public void testCollect3() {
		//单个属性分组
		Map<Status, List<Employee>> map = emps.stream()
				.collect(Collectors.groupingBy(Employee::getStatus));
		System.out.println(map);
		//多个属性进行分组  先按状态分 状态相同再按年龄段分组
		Map<Status, Map<String, List<Employee>>> collect = emps.stream()
				.collect(Collectors.groupingBy(Employee::getStatus,Collectors.groupingBy((x)->{
					if(((Employee)x).getAge()<35) {
						return "青年";
					}else if(((Employee)x).getAge()<=50) {
						return "中年";
					}else {
						return "老n";
					}
				})));
		System.out.println(collect); 

	}
}
练习:
import java.util.Arrays;
import java.util.Optional;

import org.junit.Test;

/**
 * stream练习:
 * @author Administrator
 *
 */
public class TestStreamPractice {
	/**
	 * 练习一:给定一个数字列表,如何返回每个数的平方组成的新的数组
	 * {1,2,3,4,5}
	 */
	@Test
	public void test01() {
		Integer [] nums = new Integer[] {1,2,3,4,5};
		
		Arrays.stream(nums)
				.map((e)->e * e)
				.forEach(System.out::println);
	}
	
	/**
	 * 练习二:使用map和reduce进行统计流中有多少个元素
	 */
	@Test
	public void test02() {
		Integer [] nums = new Integer[] {1,2,3,4,5};
		
		Optional<Integer> reduce = Arrays.stream(nums)
				.map((e)->1)
				.reduce(Integer::sum);
		System.out.println(reduce.get());
	}
}
四:并行流
并行流:就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流

Java8中将并行进行了优化,我们可以很容易对数据进行并行的操作。Stream API可以声明性的通过parallel()与sequential()在并行流和顺序流之间进行切换

了解FORK/JOIN框架
FORK/JOIN框架就是在必要的情况下,将一个大任务,进行拆分成若干个小任务(拆到不可再拆时),再将一个个的运算结果进行join汇总。

ForkJoin框架案例

/**
 * 使用ForkJoin框架来进行运算
 * @author Administrator
 *
 */
public class ForkJoinCaculate extends RecursiveTask<Long>{

	private static final long serialVersionUID = 1L;
	/**
	 * 起始值
	 */
	private long start;
	/**
	 * 结束值
	 */
	private long end;
	/**
	 * 临界值
	 */
	private static final long THRESHOLD = 10000L;
	/**
	 * 运算
	 */
	@Override
	protected Long compute() {
		long length = end -start;
		//如果差值小于临界值说明已经不可再拆分直接进行求值
		if(length < THRESHOLD) {
			
			long sum = 0;
			
			for (long i = start; i <= end; i++) {
				sum += i;
			}
			
			return sum;
		}else {//说明还可以在进行拆分
			long midel = (start + end)/2;
			
			ForkJoinCaculate left = new ForkJoinCaculate(start ,midel);
			ForkJoinCaculate right = new ForkJoinCaculate(midel+1 ,end);
			
			ForkJoinTask<Long> forkLeft = left.fork();//进行任务的拆分,并压入自己的线程队列
			ForkJoinTask<Long> forkRight = right.fork();//进行任务的拆分,并压入自己的线程队列
			
			return forkLeft.join() + forkRight.join();//将结果进行汇总
		}
	}
	public ForkJoinCaculate(long start, long end) {
		super();
		this.start = start;
		this.end = end;
	}	
}


import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.LongStream;

import org.junit.Test;

/**
 * 进行FORK JOIN 的测试
 * 使用FORK JOIN时数据要足够的大才能有效果
 * 并且临界值也要选一个合适的值
 * @author Administrator
 *
 */
public class ForkJoinTest {
	/**
	 * 使用1.8中的并行流
	 */
	@Test
	public void test03() {
		//统计耗时
		Instant start = Instant.now();
		long reduce = LongStream.rangeClosed(0, 50000000000L)
				.parallel()//切换为并行流
				.reduce(0,Long::sum);
		Instant end = Instant.now();
		Duration between = Duration.between(start, end);
		System.out.println("本次计算的耗时     "+ between.toMillis());
		System.out.println("计算的结果是 = "+ reduce);
	}
	/**
	 * 使用ForkJoin
	 */
	@Test
	public void test02(){//54719
		//统计耗时
		Instant start = Instant.now();
		//创建线程池
		ForkJoinPool forkJoinPool = new ForkJoinPool();
		//创建一个任务
		ForkJoinTask<Long> task = new ForkJoinCaculate(1, 50000000000L);
		//提交任务

		Long sum = forkJoinPool.invoke(task);
		Instant end = Instant.now();

		Duration between = Duration.between(start, end);
		System.out.println("本次计算的耗时     "+ between.toMillis());
		System.out.println("计算的结果是 = "+ sum);
	}
	/**
	 * 使用单线程
	 */
	@Test
	public void test01 (){// 29607
		//统计耗时
		Instant start = Instant.now();
		long sum = 0;
		for (long i = 1; i <= 50000000000L; i++) {
			sum += i;
		}
		Instant end = Instant.now();

		Duration between = Duration.between(start, end);
		System.out.println("本次计算的耗时     "+ between.toMillis());
		System.out.println("计算的结果是 = "+ sum);
	}
}
六:Java8中新的容器类Optional

Optional类是Java.util.Optional是一个容器类,代表一个值存在或不存在,原来使用一个NULL值表示不存在,现在Optional可以更好的表示这个概念。并且可以避免空指针异常。

常用的方法:

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

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

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

isPresent():判断是否包含空值

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

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

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

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

import java.util.Optional;
import org.junit.Test;
import com.Employee;

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

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

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

	isPresent():判断是否包含空值

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

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

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

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

 * @author Administrator
 *
 */
public class TestOptional {
	@Test
	public void test01() {
		//这种方式不能直接构建一个Optional类直接报错
		Optional<Employee> op= Optional.of(new Employee());
		Employee employee = op.get();
		System.out.println(employee);
		
		//该方法中不能直接传一个null值
//		Optional<Employee> op1= Optional.of(null);
//		Employee employee1 = op1.get();
		
		//可以使用ofNullable创建一个空实例若T不为空创建一个Optional实例,否则创建一个空实例
		Optional<Employee> op3= Optional.ofNullable(new Employee());
		Employee employee3 = op3.get();
		
		
		Optional<Employee> op2= Optional.ofNullable(null);
		if(op2.isPresent()) {
			Employee employee2 = op2.get();			
		}
	}
	
	@Test
	public void test02() {
	
		Optional<Employee> op= Optional.of(new Employee());
		/**
		 * 如果op中有值则返回该值,如果没有值则创建一个张三
		 * 可以使用这种的方式能够避免空指针异常
		 */
		Employee orElse = op.orElse(new Employee("张三"));
		System.out.println(orElse);
		
		//演示没有值的操作
		Optional<Employee> op2= Optional.ofNullable(null);
		Employee orElse2 = op2.orElse(new Employee("张三"));
		System.out.println(orElse2);
	}
	
	
	@Test
	public void test03() {
		//使用供给型接口
		Optional<Employee> op = Optional.ofNullable(null);
		Employee orElseGet = op.orElseGet(Employee::new);
		System.out.println(orElseGet);
	}
	
	@Test
	public void test04() {
		/**
		 * 	map(Function  f)如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty()
			flatMap( Function  mapper)与map类似,要求返回的必须是Optional
			两者的区别在于:map可以返回任意类型,而flatMap必须返回Optional类型的值
		 */
		Optional<Employee> op = Optional.ofNullable(new Employee("张三"));
		Optional<String> map = op.map((e)->e.getName());
		System.out.println(map.get());
		
		//这里就是map和flatMap的区别
		Optional<Employee> op1 = Optional.ofNullable(new Employee("张三"));
		Optional<String> map1 = op1.flatMap((e)->Optional.of(e.getName()));
		System.out.println(map1.get());

	}

	private Object Ontinal(String name) {
		// TODO Auto-generated method stub
		return null;
	}
}
七:JAVA8中新的接口定义方式:可以定义 default方法和 静态方法
  1. 继承抽象类并实现接口
/**
 * JDK8 中新的接口定义方式
 * @author Administrator
 *当子类既继承了抽象了的getName()由实现了接口中方法时要遵循类优先的原则
 */
public class TestNewInterface extends Myabstract implements Myinterface{
	/**
	 * 当子类既继承了抽象了的getName()由实现了接口中方法时要遵循类优先的原则
	 */
	public  void getName() {
		super.getName();
	}
	public static void main(String[] args) {
		new TestNewInterface().getName();
	}
}

interface Myinterface{
	default void getName() {
		System.out.println("Myinterface");
	}
}
abstract class Myabstract{
	public void getName() {
		System.out.println("Myabstract");
	}
}
  1. 实现多个接口的操作
/**
 * JDK8 中新的接口定义方式
 * @author Administrator
 *
 */
public class TestNewInterface implements Myinterface,Myinterface1{
	/**
	 * 当子类实现了两个接口时接口中存在相同的方法名时处理方式
	 * 接口名称+super+方法名
	 */
	public  void getName() {
		Myinterface1.super.getName();
	}
	public static void main(String[] args) {
		new TestNewInterface().getName();
	}
	
	/**
	 * 当类实现写两个接口中存在相同方法明时想要调用对应的方法我们就要采取
	 * 接口名.super.方法名的方式
	 */
}

interface Myinterface{
	default void getName() {
		System.out.println("Myinterface");
	}
}
interface Myinterface1{
	default void getName() {
		System.out.println("Myinterface1");
	}
}
八:Java8中新的时间API
案例一:原来时间API中存在的线程安全问题
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
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.junit.Test;

/**
 * 测试原来的时间API的线程安全问题
 * @author Administrator
 *
 */
public class TestSimpleDataFormat {
	/**
	 * 使用和当前线程绑定的方式解决线程安全问题
	 * @throws ExecutionException 
	 * @throws InterruptedException 
	 */
	@Test
	public void test02() throws InterruptedException, ExecutionException {
		Callable<Date> task = new Callable<Date>() {

			@Override
			public Date call() throws Exception {
				return DateFormatThreadLocal.convert("20181213");
			}
		};
		ExecutorService pool = Executors.newFixedThreadPool(10);
		
		List<Future<Date>> results = new ArrayList<Future<Date>>();
		
		for (int i = 0; i < 10; i++) {
			results.add(pool.submit(task));
		}
		System.out.println(results);
		for (Future<Date> future : results) {
			System.out.println(future.get());
		}
		
//		pool.shutdown();
	}
	
	/**
	 * 展示原来的api中存在的线程安全问题
	 * @param args
	 * @throws InterruptedException
	 * @throws ExecutionException
	 */
	@Test
	public void test1() throws InterruptedException, ExecutionException {
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
		Callable<Date> task = new Callable<Date>() {

			@Override
			public Date call() throws Exception {
				return simpleDateFormat.parse("20190603");
			}
		};
		ExecutorService pool = Executors.newFixedThreadPool(10);
		
		List<Future<Date>> results = new ArrayList<>();
		
		for (int i = 0; i < 10; i++) {
			results.add(pool.submit(task));
		}
		
		for (Future<Date> future : results) {
			System.out.println(future.get());
		}
		
//		pool.shutdown();
	}
}

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
 * 使用和当前线程绑定的方式解决线程安全问题
 * @author Administrator
 *
 */
public class DateFormatThreadLocal {
	private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>();


	public DateFormat initialValue() {
		return new SimpleDateFormat("yyyyMMdd");
	}
	
	public static Date convert(String source) throws ParseException {
		return df.get().parse(source);
	}
}
案例二:新的时间API的使用一:创建
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.Period;
import java.time.ZoneOffset;

import org.junit.Test;

public class TestNewAPI {
	
	/**
	 * 	时间的计算
	 */
	@Test
	public void test03() {
		/**
		 * 	计算另个Instnt类型之间的时间间隔使用Duration
		 */
		Instant start = Instant.now();
		int sum = 0;
		for (int i = 0; i < 1000; i++) {
			sum += i;
			System.out.println(sum);
		}
		Instant end = Instant.now();
		Duration between = Duration.between(start, end);
		System.out.println("本次执行耗秒数"+between.toMillis() +"   纳秒数      "+between.toNanos());

		/**
		 * 	计算两个日期之间的时间间隔
		 */
		LocalDate st1 = LocalDate.of(2016, 4, 23);
		LocalDate now = LocalDate.now();
		
		Period between2 = Period.between(st1, now);
		System.out.println(between2.getYears()+"年"+between2.getMonths()+"月"+between2.getDays());
		
		
	}
	
	
	/**
	 *	返回时间错
	 *	Instant  返回机读的时间戳  返回的时间戳是以UTC时区为准的  不是我们系统时间		
	 */
	@Test
	public void test02() {
		Instant utcTime = Instant.now();//返回的UTC时区的时间
		System.out.println(utcTime);
		
		//使用带偏移量的时间戳
		OffsetDateTime atOffset = utcTime.atOffset(ZoneOffset.ofHours(8));
		System.out.println(atOffset);
		
		long epochMilli = utcTime.toEpochMilli();//返回时间的毫秒数
		System.out.println(epochMilli);
		
	}

	/**
	 * 	返回的是人读的时间
	 * LocalDate   LocalTime  LocalDateTime
	 */
	@Test
	public void test01() {
		LocalDate now = LocalDate.now();
		System.out.println("LocalDate  "+now);

		LocalTime now2 = LocalTime.now();
		System.out.println("LocalTime   "+now2);

		LocalDateTime now3 = LocalDateTime.now();
		System.out.println("LocalDateTime  "+now3);

		LocalDateTime of = LocalDateTime.of(2018, 12, 12, 11, 11, 11);
		System.out.println("LocalDateTime.of()   "+of);

		/**
		 * 时间的设置
		 */
		LocalDateTime now4 = LocalDateTime.now();
		LocalDate now5 = LocalDate.now();
		LocalDateTime plusDays = now4.plusDays(11);//当前时间之上增加11天
		System.out.println(plusDays);
		
		LocalDate minusMonths = now5.minusMonths(1);//当前日期减去一个月
		System.out.println(minusMonths);
	}
}
案例三:新的时间API的使用二:日期的操作
import org.junit.Test;
/**
 * 	日期的操作
 * 	TemporalAdjuster时间矫正器。有时我们可能要获取
 * 	例如:例如将日期调整到下个周日的操作
 * 	
 * 
 * TemporalAdjusters:该类通过静态方法提供了大量的常用
 * 	TemporalAdjuster的实现
 * @author Administrator
 *
 */
public class TestNewAPI2 {

	/**
	 * 	TemporalAdjusters的使用
	 */
	@Test
	public void test01() {
		//返回下周末的操作
		LocalDate nextSunday = LocalDate.now().with(
				TemporalAdjusters.next(DayOfWeek.SUNDAY));
		System.out.println("返回下周末的LocalDate     " +nextSunday);
		
		//自定义实现下一个工作日
		LocalDate nextWorkDay = LocalDate.now().with((e)->{
			LocalDate now=(LocalDate)e;
			DayOfWeek dayOfWeek = now.getDayOfWeek();
			if(dayOfWeek.equals(DayOfWeek.FRIDAY)) {
				return now.plusDays(3);
			}else if(dayOfWeek.equals(DayOfWeek.SATURDAY)){
				return now.plusDays(2);
			}else {
				return now.plusDays(1);
			}
		});
		System.out.println("下一个工作日   "+nextWorkDay);
	}
}
案例四:带时区的时间
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Set;

import org.junit.Test;
/**
 * 	带时区的时间
 * ZonedDateTime
 */
public class TestNewAPI3 {

	
	/**
	 * 	使用类中指定的标准进行格式化
	 */
	@Test
	public void test01() {
		ZonedDateTime now = ZonedDateTime.now();
		System.out.println(now);
		
		Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
		for (String string : availableZoneIds) {
			System.out.println(string);
		}
		
		LocalDateTime now2 = LocalDateTime.now(ZoneId.of("Canada/East-Saskatchewan"));
		System.out.println(now2);
	}
}
案例五:时间日期的格式化
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import org.junit.Test;
/**
 * 	时间日期的格式化
 *	DateTimeFormatter
 */
public class TestNewAPI4 {
	/**
	 * 	使用自定义的方式进行格式化
	 */
	@Test
	public void test02() {
		DateTimeFormatter isoDateTime = DateTimeFormatter.ofPattern("yyyy年MM月dd日  HH:mm:ss");
		
		LocalDateTime now = LocalDateTime.now();
		String format = now.format(isoDateTime);

		System.out.println(format);
		
		LocalDateTime parse = LocalDateTime.parse(format, isoDateTime);
		System.out.println(parse);
	}
	
	/**
	 * 	使用类中指定的标准进行格式化
	 */
	@Test
	public void test01() {
		DateTimeFormatter isoDateTime = DateTimeFormatter.ISO_DATE_TIME;
		 DateTimeFormatter isoDate = DateTimeFormatter.ISO_DATE;
		LocalDateTime now = LocalDateTime.now();
		String format = now.format(isoDateTime);
		String format2 = now.format(isoDate);
		
		System.out.println(format);
		System.out.println(format2);
		
	}
}

九:注解之重复注解的定义

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 	测试创建重复注解
 * 	意思是:同一个注解不能再同一个位置上出现两次
 * 	解决办法:使用容器(并且要使用  {@link AnotationContainer})
 * @author Administrator
 *
 */
@Repeatable(value =AnotationContainer.class)//使用重复注解必须声明此注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})
public @interface MyAnotation {
	
	String value() default "google";
}


/**
 * 	这个注解是MyAnotation的容器
 * @author Administrator
 *
 */

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})
public @interface AnotationContainer {
	
	MyAnotation [] value();
	
}

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import org.junit.Test;
/**
 * 	时间日期的格式化
 *	DateTimeFormatter
 */
public class TestNewAPI4 {
	/**
	 * 	使用自定义的方式进行格式化
	 */
	@Test
	public void test02() {
		DateTimeFormatter isoDateTime = DateTimeFormatter.ofPattern("yyyy年MM月dd日  HH:mm:ss");
		
		LocalDateTime now = LocalDateTime.now();
		String format = now.format(isoDateTime);

		System.out.println(format);
		
		LocalDateTime parse = LocalDateTime.parse(format, isoDateTime);
		System.out.println(parse);
	}
	
	/**
	 * 	使用类中指定的标准进行格式化
	 */
	@Test
	public void test01() {
		DateTimeFormatter isoDateTime = DateTimeFormatter.ISO_DATE_TIME;
		 DateTimeFormatter isoDate = DateTimeFormatter.ISO_DATE;
		LocalDateTime now = LocalDateTime.now();
		String format = now.format(isoDateTime);
		String format2 = now.format(isoDate);
		
		System.out.println(format
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值