Java 8特性

目录

一、Java8中Interface接口

二、Lambda 表达式

三、函数式接口 Functional Interface

1、函数式接口

2、内置函数式接口(Built-in Functional Interfaces)

(1)Predicate接口

(2)Function接口

(3)Comparator接口

四、Stream流 

 1、Filter 过滤

2、Sorted 排序

3、Map 映射

4、Match 匹配

5、Count 计数

 6、Distinct 去重

7、Collect 收集

(1)Collectors.mapping()

(2)Collectors.groupingBy()和Collectors.partitioningBy()

8、Statistics 统计

 9、Parallel Streams 并行流

五、日期时间

1、格式化

2、字符串转日期格式

3、日期计算

4、获取指定日期

总结



一、Java8中Interface接口

interface接口 的设计目的是面向接口编程,提高扩展性。

Java8中,接口中除了抽象方法外,还可以定义default默认方法和static静态方法。

default修饰的默认方法,属于实例方法,可以被实现类调用或重写。

(1)调用:实现类必须implements接口,才能调用该接口的default默认方法。

(2)重写:实现类implements不同接口时,接口中存在相同签名的方法(名称、参数、类型完全一致),则实现类必须重写该方法,明确方法定义;

static修饰的静态方法,属于类的静态方法。但它不能被子类继承,只能用interface接口名称调用。

二、Lambda 表达式

Lambda 表达式本质是一个匿名函数,用于把函数作为参数,传入方法中,实现函数式编程风格。

使用Lambda 表达式可以使代码变的更加简洁紧凑。

语法格式:(parameters)-> expression 或 (parameters)->{ statements;}

案例:对集合里面的内容排序

public class Demo01 {
	public static void main(String[] args) {
		
		List<String> list = Arrays.asList("as", "ab", "asc", "adcde");

		list.sort((o1, o2) -> {
			if (o1.length() == o2.length()) {
				return o1.compareTo(o2);
			}
			return o1.length() - o2.length();
		});
		
		System.out.println(list);
		
	}
}

输出结果:

三、函数式接口 Functional Interface

1、函数式接口

只有一个抽象方法的接口(可以定义多个非抽象方法)。可以使用@FunctionalInterface接口定义,强化语义规范。

函数式接口,也被称为SAM 接口(Single Abstract Method Interfaces)。

作用:基于函数式接口,可以使用Lambda表达式进行实现,实现函数式编程。

函数式接口Comparator:

示例1:排序(使用Lambda实现函数式接口)

// lambda表达式实现字符串数组排序
Arrays.sort(array, (x1,x2) -> {
    if (x1.length() != x2.length()) {
        return x1.length() - x2.length();
    } else {
        return x1.compareTo(x2);
    }
} );

示例2:迭代(使用Lambda迭代遍历集合)

List<String> langList = Arrays.asList("Basic","QBasic","c","c++","PowerBuilder","Visual Basic");
		
langList.forEach((name)->{
    System.out.println(name);
});
2、内置函数式接口(Built-in Functional Interfaces)

在 Java 8 中专门有一个包放函数式接口java.util.function,该包下的所有接口都有 @FunctionalInterface 注解,提供函数式编程方式。

(1)Predicate接口

Predicate接口是只有一个参数的返回布尔类型值的断言型接口。该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与and,或or,非negate)

public class Demo04 {
	public static void main(String[] args) {
		List<String> langList = Arrays.asList("Basic", "QBasic", 
				"C", "C++", "PowerBuilder", "C#", "gogo@");

		// 判断长度是否等于5
		Predicate<String> predicate1 = (lang) -> {
			return lang.length() != 5;
		};

		// 判断是否含有处字母以外的其它字符
		Predicate<String> predicate2 = (lang) -> {
			for (int i = 0; i < lang.length(); i++) {
				if (!Character.isLetter(lang.charAt(i))) {
					return true;
				}
			}
			return false;
		};
		
		Predicate<String> predicate3 = predicate1.and(predicate2);// 逻辑与
		Predicate<String> predicate4 = predicate1.or(predicate2);// 逻辑或
		Predicate<String> predicate5 = predicate1.negate();// 逻辑非

		// 遍历判断
		langList.forEach((lang) -> {
			// 根据不同的需求选用不同的实例对象
			if (predicate5.test(lang)) { // 输出长度等于5的字符串
				System.out.println(lang);
			}
		});
	}
}

输出结果:

(2)Function接口

Function 接口接受一个参数并生成结果。默认方法可用于将多个函数链接在一起(compose, andThen)。

public class Demo06 {
	public static void main(String[] args) {
		List<String> langList = Arrays.asList("Basic", "QBasic", "C", "C++", "PowerBuilder", "C#", "gogo@");

		Function<String, String> function1 = (lang)->{
			return lang.toLowerCase();// 将集合中的字符转换为小写
		};
		
		Function<String, String> function2 = (lang)->{
			return String.format("<%s>", lang);// 将集合中的每个字符串两边分别拼接"<"和">"
		};
		
		// 合并操作
		Function<String, String> function3 = function1.andThen(function2);// 先执行function1,再执行function2
		Function<String, String> function4 = function1.compose(function2);// 先执行function2,再执行function1
		
		langList.stream().map(function4).forEach((lang)->{
			System.out.println(lang);
		});

	}
}

输出结果:

(3)Comparator接口

比较器接口,用于比较指定元素值的大小。Java8版本中,添加了多个新的default方法,用于比较器合并、反转等操作。

public class Demo07 {
	public static void main(String[] args) {
		List<String> langList = Arrays.asList("Basic", "QBasic", "c", "C++", "PowerBuilder", "C#", "gogo@");
		
		// 按照内容比较
		Comparator<String> comparator1 = (x,y)->{
			return x.compareTo(y);
		};
		
		// 按照长度比较
		Comparator<String> comparator2 = (x,y)->{
			return x.length()-y.length();
		};
		
		// 先比较内容,再比较长度
		Comparator<String> comparator3 = comparator1.thenComparing(comparator2);
		
		// 按照长度比较(逆序)
		Comparator<String> comparator4 = comparator2.reversed();
		
		langList.sort(comparator4);
		System.out.println(langList);
	}
}

输出结果:

四、Stream流 

java.util.Stream 表示能应用在一组元素上一次执行的操作序列。

Stream操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回Stream本身,可以连续完成多个操作。

 1、Filter 过滤

过滤通过一个predicate接口来过滤并只保留符合条件的元素,该操作属于中间操作。所以过滤后的结果,可以继续进行其它Stream操作(例如forEach,forEach需要一个函数来对过滤后的元素依次执行。forEach是一个最终操作)。

public class Demo03 {
	public static void main(String[] args) {
		List<String> langList = Arrays.asList("Basic", "QBasic", "C", "C++", "PowerBuilder", "C#");

		// 过滤出长度等于1或等于2的字符串输出
		langList.stream().filter((lang) -> {
			return lang.length() == 1 || lang.length() == 2;
		}).forEach((lang) -> {
			System.out.println(lang);
		});
	}
}

输出结果:

2、Sorted 排序

排序是一个 中间操作,返回的是排序好后的 Stream。(不影响原数据)

public class Demo18 {
	public static void main(String[] args) {
		List<String> list = Arrays.asList("abc", "def", "gkh", "abc");

		// 排序并遍历
		list.stream().sorted().forEach((str) -> {
			System.out.println(str);
		});
	}
}

输出结果:

3、Map 映射

映射是一个中间操作, 会将元素根据指定的 Function 接口来依次将元素转成另外的对象。

public class Demo05 {
	public static void main(String[] args) {
		List<String> langList = Arrays.asList("Basic", "QBasic", "C", "C++", "PowerBuilder", "C#", "gogo@");

		langList.stream().map((lang) -> {
//			return lang.toLowerCase();// 将集合中的元素转换为小写
			return lang.length();// 集合中元素的长度 => 输出相应的长度
		}).forEach((lang) -> {
			System.out.println(lang);
		});

	}
}

输出结果:

4、Match 匹配

Stream提供了多种匹配操作,允许检测指定的Predicate是否匹配整个Stream。所有的匹配操作都是最终操作,并返回一个 boolean 类型的值。

public class Demo08 {
	public static void main(String[] args) {
		List<String> list = Arrays.asList("七里香", "双截棍", "夜曲", "青花瓷");

		// 局部匹配:是否存在1个名称长度为2的歌曲
		boolean isContains1 = list.stream().anyMatch((music) -> {
			return music.length() == 2;
		});

		// 全局匹配:所有歌曲名称的长度是否都为2
		boolean isContains2 = list.stream().allMatch((music) -> {
			return music.length() == 3;
		});

		// 全局匹配:所有歌曲名称的长度是否都不为2
		boolean isContains3 = list.stream().noneMatch((music) -> {
			return music.length() == 3;
		});

		System.out.println(isContains1);
		System.out.println(isContains2);
		System.out.println(isContains3);
}

输出结果:

5、Count 计数

计数是一个 最终操作,返回Stream中元素的个数,返回值类型是 long。

public class Demo19 {
	public static void main(String[] args) {
		String[] array = { "七里香", "双截棍", "夜曲", "青花瓷" };
		
		// 将数组转换为流
		long count = Arrays.stream(array).filter((music) -> {// 过滤出名称长度为3的歌曲
			return music.length() == 3;
		}).count();// 统计过滤后的结果数量
		
		System.out.println(count);
	}
}

输出结果:

 6、Distinct 去重
public class Demo09 {
	public static void main(String[] args) {
		String[] array = { "七里香", "双截棍", "夜曲", "青花瓷", "听妈妈的话", "七里香", "夜曲" };
		System.out.println("名字最长的歌曲是:");
		// distinct():去重
		// findFirst().get():得到第一个元素的值
		// max():获取最大值

		String musicName1 = Arrays.stream(array).distinct().sorted((x, y) -> {
			if (x.length() == y.length()) {
				return x.compareTo(y);
			}
			return y.length() - x.length();
		}).findFirst().get();
		System.out.println(musicName1);

		String musicName2 = Arrays.stream(array).distinct().max((x, y) -> {
			return x.length() - y.length();
		}).get();
		System.out.println(musicName2);
		
		System.out.println("名字最短的歌曲是:");
		String musicName3 = Arrays.stream(array).distinct().min((x, y) -> {
			return x.length() - y.length();
		}).get();
		System.out.println(musicName3);
	}
}

输出结果:

7、Collect 收集

收集是一个 最终操作,返回Stream中元素集合,返回值类型是集合(List、Set、Map)或字符串。

将Stream中的元素,收集至新集合:
Collectors.toList()
Collectors.toSet()
Collectors.toMap()

public class Demo10 {
	public static void main(String[] args) {

		String[] array = { "七里香", "双截棍", "夜曲", "青花瓷", "听妈妈的话", "七里香", "夜曲" };

		// 去重后将元素收集成一个List集合
		List<String> list = Arrays.stream(array).distinct().collect(Collectors.toList());
		System.out.println(list);

		// 将元素收集成一个Set集合(自动去重)
		Set<String> set = Arrays.stream(array).collect(Collectors.toSet());
		System.out.println(set);

		// 去重后将元素收集成一个LinkedList集合
		LinkedList<String> linkedList = Arrays.stream(array).distinct()
				.collect(Collectors.toCollection(LinkedList::new));
		System.out.println(linkedList);

		// 将元素收集成一个LinkedHashSet集合(自动去重,有序)
		LinkedHashSet<String> linkedHashSet = Arrays.stream(array).collect(Collectors.toCollection(LinkedHashSet::new));
		System.out.println(linkedHashSet);

		// 去重后将元素收集成一个Map集合
		// 方式一:
		Map<String, Integer> map1 = Arrays.stream(array).distinct().collect(Collectors.toMap((music) -> {
			return music;
		}, (music) -> {
			return music.length();
		}));
		System.out.println(map1);

		// 方式二:
		Map<String, Integer> map2 = Arrays.stream(array).distinct()
				.collect(Collectors.toMap(music -> music, music -> music.length()));
		System.out.println(map2);
	}
}

输出结果:

(1)Collectors.mapping()

将Stream中的元素,映射后,收集至新集合。

public class Demo11 {
	public static void main(String[] args) {
		List<String> strList = Arrays.asList("32", "54", "13", "53");

		List<Integer> numList = strList.stream()
				.collect(Collectors.mapping(s -> Integer.parseInt(s) * 10, Collectors.toList()));
		System.out.println(numList);
	}
}

输出结果:

(2)Collectors.groupingBy()和Collectors.partitioningBy()

Collectors.groupingBy():将Stream中的元素,分组后,收集至Map集合;

Collectors.partitioningBy():将Stream中的元素,按照判断规则,统计分区后,收集至Map集合。

public class Demo12 {
	public static void main(String[] args) {
		List<String> list = Arrays.asList("曹操", "张飞", "刘备", "曹植", "刘禅", "曹丕", "张辽", "孙权", "孙尚香");

		// 按照姓氏分组
		Map<Character, List<String>> map1 = list.stream().collect(Collectors.groupingBy(name -> name.charAt(0)));
		System.out.println(map1);

		// 按照名字长度是否为2分区
		Map<Boolean, List<String>> map2 = list.stream().collect(Collectors.partitioningBy(name -> name.length() == 2));
		System.out.println(map2);

	}
}

输出结果:

8、Statistics 统计

统计是一个最终操作,返回Stream中元素的各类统计信息,返回值类型是 XXXConsumer。

public class Demo13 {
	public static void main(String[] args) {
		List<Integer> list = Arrays.asList(1,2,3,4);
		
		Stream<Integer> stream = list.stream();
		
		IntStream intStream = stream.mapToInt(x->x);
		
		IntSummaryStatistics statistics = intStream.summaryStatistics();
		System.out.println("最大值:"+statistics.getMax());
		System.out.println("最小值:"+statistics.getMin());
		System.out.println("平均值:"+statistics.getAverage());
		System.out.println("累加和:"+statistics.getSum());
	}
}

输出结果:

 9、Parallel Streams 并行流

Stream有串行和并行两种,串行Stream上的操作是在一个线程中依次完成,而并行Stream则是在多个线程上同时执行。

public class Demo14 {
	public static void main(String[] args) {
		int max = 1000000;
		List<String> list = new ArrayList<String>(max);
		for (int i = 0; i < max; i++) {
			list.add(UUID.randomUUID().toString());
		}

		long start = System.currentTimeMillis();
		long count = list.parallelStream().sorted().count();
		long end = System.currentTimeMillis();
		System.out.println(end - start);
		System.out.println(count);
	}
}

输出结果:

五、日期时间

Java 8在java.time 包下包含一个全新的日期和时间API。
(1)LocalDateTime   //日期+时间 format: yyyy-MM-ddTHH:mm:ss.SSS
(2)LocalDate   //日期 format: yyyy-MM-dd
(3)LocalTime  //时间 format: HH:mm:ss

1、格式化
public class Demo15 {
	public static void main(String[] args) {
		LocalDate localDate = LocalDate.now();
		LocalTime localTime = LocalTime.now().withNano(0);
		LocalDateTime localDateTime = LocalDateTime.now();
		
		System.out.println(String.format("当前日期:%s", localDate));
		System.out.println(String.format("当前时间:%s", localTime));
		System.out.println(String.format("当前时间:%s", localDateTime));
}

输出结果:

2、字符串转日期格式
public class Demo20 {
	public static void main(String[] args) {
		LocalDate date1 = LocalDate.of(2023, 8, 20);
		LocalDate date2 = LocalDate.parse("2023-08-20");
		System.out.println(date1);
		System.out.println(date2);

		LocalDateTime dateTime1 = LocalDateTime.of(2023, 8, 20, 12, 12, 22);
		LocalDateTime dateTime2 = LocalDateTime.parse("2023-08-20T12:12:22");
		System.out.println(dateTime1);
		System.out.println(dateTime2);

		LocalTime time1 = LocalTime.of(15, 22, 14);
		LocalTime time2 = LocalTime.parse("15:22:14");
		System.out.println(time1);
		System.out.println(time2);
	}
}

输出结果:

3、日期计算
public class Demo16 {
	public static void main(String[] args) {
		// 计算一周后的日期
		LocalDate localDate = LocalDate.now();

		// 方法1
		LocalDate after1 = localDate.plus(1, ChronoUnit.WEEKS);
		System.out.println("一周后日期:" + after1);

		// 方法2
		LocalDate after2 = localDate.plusWeeks(1);
		System.out.println("一周后日期:" + after2);

		// 计算两个日期间隔多少天,计算间隔多少年,多少月
		LocalDate date1 = LocalDate.parse("2023-02-26");
		LocalDate date2 = LocalDate.parse("2023-12-23");
		Period period = Period.between(date1, date2);
		System.out.println("date1 到 date2 相隔:" + period.getYears() + "年" + period.getMonths() + "月" + period.getDays() + "天");

		// 计算两个日期间隔多少天
		long day = date2.toEpochDay() - date1.toEpochDay();
		System.out.println(date2 + "和" + date2 + "相差" + day + "天");
	}
}

输出结果:

4、获取指定日期
public class Demo17 {
	public static void main(String[] args) {
		LocalDate today = LocalDate.now();
		
		// 获取当前月第一天:
		LocalDate firstDayOfThisMonth = today.with(TemporalAdjusters.firstDayOfMonth());
		System.out.println("当前月第一天:" + firstDayOfThisMonth);

		// 获取本月最后一天
		LocalDate lastDayOfThisMonth = today.with(TemporalAdjusters.lastDayOfMonth());
		System.out.println("本月最后一天:" + lastDayOfThisMonth);

		// 获取下一天:
		LocalDate nextDay = lastDayOfThisMonth.plusDays(1);
		System.out.println("下一天(次月第一天):" + nextDay);

		// 获取当年最后一天
		LocalDate lastday = today.with(TemporalAdjusters.lastDayOfYear());
		System.out.println("当前月第一天:" + lastday);

		// 获取当年最后一个周日
		LocalDate lastMondayOfThisYear = lastday.with(TemporalAdjusters.lastInMonth(DayOfWeek.SUNDAY));
		System.out.println("当年最后一个周日:" + lastMondayOfThisYear);
	}
}

输出结果:

总结

1、Java 8中,接口中除了抽象方法外,还可以定义default默认方法和static静态方法。

2、Java 8支持使用Lambda表达式,实现函数式编程风格。

3、函数式接口

(1)Predicate、Function、Comparator;
(2)通过链式编程,使得它可以方便地对数据进行链式处理;
(3)方法参数都是函数式接口类型;
(4)一个 Stream 只能操作一次,操作完就关闭了,继续使用这个 Stream 会报错;
(5)Stream 不保存数据,不改变数据源。

4、Java 8在java.time 包下包含一个全新的日期和时间API。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值