java8笔记

一、Lambda表达式

1.语法格式

Lambda是匿名函数,可以传递代码。使用“->”操作符,改操作符将lambda分成两部分:

左侧:指定了 Lambda 表达式需要的所有参数

右侧:指定了 Lambda 体,即 Lambda 表达式要执行的功能,也就是实现接口方法的代码

// 语法格式一:无参、无返回值
	@Test
	public void test1() {
		Runnable runable = () -> System.out.println("hello lambda!");
		runable.run();
	}

	// 语法格式二:有一个参、无返回值
	@Test
	public void test2() {
		Consumer<String> consumer = (args) -> System.out.println("hello!"
				+ args);
		consumer.accept("lambda");
	}

	// 语法格式三:有多个参、有返回值,并且有多条执行语句,用大括号包围
	@Test
	public void test3() {
		Comparator<Integer> com = (x, y) -> {
			System.out.println("hello lambda!");
			return Integer.compare(x, y);
		};
		int rs = com.compare(2, 2);
		System.out.println(rs);
	}

	// 语法格式四:右侧如果只有一条执行语句,可以省略大括号和return
	@Test
	public void test4() {
		Comparator<Integer> com = (Integer x, Integer y) -> Integer.compare(x, y);
		int rs = com.compare(2, 2);
		System.out.println(rs);
	}

注:lambd可以省略接口参数类型,java编译器会根据上下文进行类型推断

2.函数式接口

(1)只包含一个抽象方法的接口,称为函数式接口,可以在任意函数式接口上使用 @FunctionalInterface 注解,lambda需要函数式接口的支持。

(2)java8内置四大核心函数式接口:

Consumer<T>消费型接口:void accept(T t)

@Test
    public void test2() {
        Consumer<String> consumer = (args) -> System.out.println("hello!"
                + args);
        consumer.accept("lambda");
    }
Supplier<T>供给型接口:T get()

@Test
	public void test5() {
		List<Integer> rs=getNumList(6,() -> (int)(Math.random()*100));
		System.out.println(rs);
	}
	public List<Integer> getNumList(int size,Supplier<Integer> sup){
		List<Integer> list=new ArrayList<Integer>();
		for (int i = 0; i < size; i++) {
			Integer e=sup.get();
			list.add(e);
		}
		return list;
	}

Function<T, R>函数型接口:R apply(T t)

@Test
	public void test6() {
		Function<String, Integer> fun=(str)->str.length();
		int len=fun.apply("lambda");
		System.out.println(len);
	}
Predicate<T>断定型接口:boolean test(T t)
@Test
	public void test7() {
		Predicate<String> check=(str)->str.equals("lambda");
		boolean rs=check.test("lambda");
		System.out.println(rs);
	}

3.方法引用

当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!( lambda要实现抽象方法的参数列表,必须与方法引用的方法参数列表保持一致! )。
方法引用:使用操作符 “ ::” 将对象或类和方法的名字分隔开来。

三种主要使用情况:

对象::方法名

PrintStream ps=System.out;
		Consumer<String> consumer =  ps::println;
		consumer.accept("lambda");
类::静态方法名

Comparator<Integer> com = Integer::compare;
		int rs = com.compare(2, 2);
		System.out.println(rs);
类::实例方法名(前提条件:lambda参数列表的第一个参数是实例方法的调用者,第二个参数是实例方法的入参)

BiPredicate<String,String> check=(str1,str2)->str1.equals(str2);
		BiPredicate<String,String> check1=String::equals;

4.构造器引用

与函数式接口相结合,自动与函数式接口中方法兼容(需要调用的构造器方法参数列表要与函数式接口中方法的参数列表一致)

格式: ClassName::new

5.数组引用

格式: type[] :: new

二、Stream API

1.说明解释

Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。流(Stream)是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。“集合讲的是数据,流讲的是计算! ”

注意:
①Stream 自己不会存储元素。
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

2.Stream 操作步骤

(1)创建Stream

①可以通过Collection系列集合提供的stream()或者parallelStream()获得

List<String> list=new ArrayList<String>();
		Stream<String> stream=list.stream();
②可以通过Arrays的静态方法stream()获得数组流
Person[] ps=new Person[10];
		Stream<Person> stream=Arrays.stream(ps);
③可以通过Stream的静态of()
Stream<String> steam=Stream.of("aa","bb","cc");
④可以使用静态方法 Stream.iterate() 和Stream.generate(), 创建无限流

(2)中间条件操作

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

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

List<Person> personList = Arrays.asList(
				new Person("李四", 20, 10),
				new Person("张三", 40,30),
				new Person("王五", 28, 15),
				new Person("赵六", 60, 60),
				new Person("赵六", 60, 60),
				new Person("赵六", 60, 60),
				new Person("田七", 8,2)
		);
		
		Stream<Person> stream=personList.stream();		
		stream.filter((p)->p.getAge()>20)//过滤保留age>20
		.limit(5)//只取前两个
		.skip(1)//跳过前一个,返回剩下的
		.distinct()//去重,自动定义对象去重要重写equals和hashcode
		.forEach(System.out::println);

②映射
        map——接收 Lambda,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
        flatMap——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流

Stream<Person> stream=personList.stream();        
        stream.map((p)->p.getName())//提取name,组成新的Stream流
        .forEach(System.out::println);
③排序
        sorted()——自然排序(Comparable
        sorted(Comparator com)——定制排序

(3)执行操作

查找与匹配
        allMatch——检查是否匹配所有元素,返回boolean
        anyMatch——检查是否至少匹配一个元素,返回boolean
        noneMatch——检查是否没有匹配的元素,返回boolean
        findFirst——返回第一个元素
        findAny——返回当前流中的任意一个元素
        count——返回流中元素的总个数
        max——返回流中最大值
        min——返回流中最小值
        forEach——内部迭代循环

②归约
        reduce(T identity, BinaryOperator) / reduce(BinaryOperator) ——可以将流中元素反复结合起来,得到一个值。

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

3.其他

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

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

三、Optional 类

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

Optional 常用方法:
       Optional.of(T t) : 创建一个 Optional 实例
       Optional.empty() : 创建一个空的 Optional 实例
       Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
       isPresent() : 判断是否包含值
       orElse(T t) :  如果调用对象包含值,返回该值,否则返回t
       orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
       map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()
       flatMap(Function mapper):与 map 类似,要求返回值必须是Optional

四、接口类中的默认方法与静态方法

public interface MyInterface {
	//默认方法
	default void say() {
       //doSomething
	}
	//静态方法
	public static void say1() {
	  //doSomething
	}
}
1.默认方法

Java 8中允许接口中包含具有具体实现的方法,该方法称为“默认方法”,默认方法使用 default 关键字修饰。

接口默认方法的” 类优先” 原则
若一个接口中定义了一个默认方法,而另外一个父类或接口中又定义了一个同名的方法时:

  •   选择父类中的方法。如果一个父类提供了具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略。
  • 接口冲突。如果一个父接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认方法), 那么必须覆盖该方法来解决冲突

2.静态方法

  Java8 中,接口中允许添加静态方法。

五、新时间日期 API

1.LocalDateTime、LocalDate、LocalTime

//获取当前日期时间
		LocalDateTime ldt1=LocalDateTime.now();
		System.out.println(ldt1);
		//获取指定的日期时间
		LocalDateTime ldt2=LocalDateTime.of(2017, 7, 10, 14, 50);
		System.out.println(ldt2);
		//计算日期时间,当前加两年
		LocalDateTime ldt3=ldt1.plusYears(2);
		System.out.println(ldt3);
		//计算日期时间,当前减两年
		LocalDateTime ldt4=ldt1.minusYears(2);
		System.out.println(ldt4);
		System.out.println(ldt4.getYear());
		System.out.println(ldt4.getMonthValue());

2.Instant时间戳

使用 Unix 元年  1970年1月1日 00:00:00 所经历的毫秒值

Instant ins = Instant.now(); //默认使用 UTC 时区
		System.out.println(ins);
		//设置时区偏移小时
		OffsetDateTime odt = ins.atOffset(ZoneOffset.ofHours(8));
		System.out.println(odt);
		//获得毫秒数
		System.out.println(ins.toEpochMilli());
		//获得自1970-01-01 00:00:00后秒数时间
		Instant ins2 = Instant.ofEpochSecond(5);
		System.out.println(ins2);

3.Duration、Period

//Duration:计算两个“时间”之间的间隔
		LocalTime lt1=LocalTime.now();
		LocalTime lt2=LocalTime.of(16, 40);
		Duration du= Duration.between(lt1, lt2);
		System.out.println(du.toHours());
		System.out.println(du.getSeconds());
		
		//Period:用于计算两个“日期”间隔
		LocalDate ld1=LocalDate.now();
		LocalDate ld2=LocalDate.of(2017, 8, 15);
		Period p= Period.between(ld1, ld2);
		System.out.println(p.getYears());
		System.out.println(p.getMonths());
		System.out.println(p.getDays());

4.TemporalAdjuster : 时间校正器

TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整到“下个周日”等操作。
TemporalAdjusters : 该类通过静态方法提供了大量的常用 TemporalAdjuster 的实现。

// 得到下一个周一
		LocalDateTime ldt = LocalDateTime.now();
		LocalDateTime ldt1 = ldt.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
		System.out.println(ldt);		
		System.out.println(ldt1);
		
		
		// 自定义:下一个工作日
		LocalDateTime ldt5 = ldt.with((l) -> {
			LocalDateTime ldt4 = (LocalDateTime) l;
			DayOfWeek dow = ldt4.getDayOfWeek();
			if (dow.equals(DayOfWeek.FRIDAY)) {
				return ldt4.plusDays(3);
			} else if (dow.equals(DayOfWeek.SATURDAY)) {
				return ldt4.plusDays(2);
			} else {
				return ldt4.plusDays(1);
			}
		});
		
		System.out.println(ldt5);

5.DateTimeFormatter : 解析和格式化日期或时间

//DateTimeFormatter dtf = DateTimeFormatter.ISO_LOCAL_DATE;		
		DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss E");
		
		LocalDateTime ldt = LocalDateTime.now();
		String strDate = ldt.format(dtf);
		System.out.println(strDate);

6.ZonedDate、ZonedTime、ZonedDateTime : 带时区的时间或日期

ZoneId.getAvailableZoneIds():列出所有时区

ZoneId.of(""):可以获得时区



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值