Java8 特性

一、Java8中的interface接口

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

  • Java8 中,接口中除了抽象方法外,还可以定义 default 默认方法和 static 静态方法。
    • default 修饰的默认方法,属于实例方法,可以被实现类调用或重写
      • 调用:实现类必须 implements 接口,才能调用该接口的 default 默认方法。
      • 重写:实现类 implements 不同接口时,接口中存在相同签名的方法(名称、参 数、类型完全一致),则实现类必须重写该方法,明确方法定义;
    • static 修饰的静态方法,属于类的静态方法。但它不能被子类继承,只能用 inter face 接口名称调用。

二、Lambda 表达式

  • Lambda 表达式本质是一个匿名函数,用于把函数作为参数,传入方法中,实现函数式编程风格。
  • 使用 Lambda 表达式可以使代码变的更加简洁紧凑。

语法格式

(parameters)-> expression 或 (parameters)->{ statements;} 

三、函数式接口 Functional Interface

  • 只有一个抽象方法的接口(可以定义多个非抽象方法)。可以使用 @FunctionalInterface 接口定义,强化语义 规范。
  • 函数式接口,也被称为 SAM 接口( Single Abstract Method Interfaces )

作用: 

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

3.1 排序

函数式接口Comparator

@FunctionalInterface
public interface Comparator<T> {
    int compare(T o1, T o2);
}

使用Lambda实现函数式接口

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

3.2 迭代

使用Lambda迭代遍历集合

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

		List<String> list = Arrays.asList("a", "ab", "abcd", "cd");

//		list.sort(new Comparator<String>() {
//			@Override
//			public int compare(String o1, String o2) {
//				if (o1.length() == o2.length()) {
//					return o1.compareTo(o2);
//				}
//				return o1.length() - o2.length();
//			}
//		});

		// Lambda 表达式
		list.sort((s1, s2) -> {
			if (s1.length() == s2.length()) {
				return s1.compareTo(s2);
			}
			return s1.length() - s2.length();
		});

		System.out.println(list);
	}
}

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

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

3.3.1 Predicate接口

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

package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Predicate<T> {

     // 该方法是接受一个传入类型,返回一个布尔值.此方法应用于判断.
     boolean test(T t);
     // and方法与关系型运算符"&&"相似,两边都成立才返回true
     default Predicate<T> and(Predicate<? super T> other) {
         Objects.requireNonNull(other);
         return (t) -> test(t) && other.test(t);
     }

     // 与关系运算符"!"相似,对判断进行取反
     default Predicate<T> negate() {
         return (t) -> !test(t);
     }

     //or方法与关系型运算符"||"相似,两边只要有一个成立就返回true
     default Predicate<T> or(Predicate<? super T> other) {
         Objects.requireNonNull(other);
         return (t) -> test(t) || other.test(t);
     }
    
     // 该方法接收一个Object对象,返回一个Predicate类型.此方法用于判断第一个test的方法与第二个test方法相同(equal).
     static <T> Predicate<T> isEqual(Object targetRef) {
     return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object);
    }
}

示例:

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

		List<String> langList = Arrays.asList("Basic", "QBasic", "c", "C#", "c++", "PowerBuilder", "Visual Basic");

		// 条件1
		Predicate<String> predicate1 = (lang) -> {
			return lang.length() == 5;
		};

		// 条件2
		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); // 用and拼接
		Predicate<String> predicate4 = predicate1.or(predicate2); // 用or拼接
		Predicate<String> predicate5 = predicate3.negate(); // 取反
		// 方式1 调用test方法执行
//		langList.forEach((lang) -> {
//			System.out.println(lang + "是否符合条件?" + predicate5.test(lang));
//		});

		// 方式2 使用filter过滤
		langList.stream().filter(predicate3).forEach((lang) -> {
			System.out.println(lang);
		});
	}
}

3.3.2 Function接口

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

package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Function<T, R> {

     // 将Function对象应用到输入的参数上,然后返回计算结果。
     R apply(T t);

     // 将两个Function整合,并返回一个能够执行两个Function对象功能的Function对象
     // 作用等同于:apply(before.apply(v))
     default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
         Objects.requireNonNull(before);
         return (V v) -> apply(before.apply(v));
     }

     // 将两个Function整合,并返回一个能够执行两个Function对象功能的Function对象
     // 作用等同于:before.apply(apply())
     default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
         Objects.requireNonNull(after);
         return (T t) -> after.apply(apply(t));
     }
}

示例:

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

		List<String> langList = Arrays.asList("Basic", "QBasic", "c", "C#", "c++", "PowerBuilder", "Visual Basic");

		Function<String, String> function1 = (lang) -> {
			System.out.println("fun1");
			return lang.toUpperCase();
		};

		Function<String, String> function2 = (lang) -> {
			System.out.println("fun2");
			return lang.format("<%s>", lang);
		};

		// 组合方式1 先fun1 后fun2
		Function<String, String> function3 = function1.andThen(function2);
		// 组合方式2 先fun2 后fun1
		Function<String, String> function4 = function1.compose(function2);

		langList.stream().map(function3).forEach((lang) -> {
			System.out.println(lang);
		});
	}
}

3.3.3 Comparator

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

示例:

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

		List<String> langList = Arrays.asList("Basic", "QBasic", "c", "C#", "c++", "PowerBuilder", "Visual Basic");

		// 按照内容比较
		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 = comparator1.reversed();

		langList.sort(comparator4);
		System.out.println(langList);
	}
}

四、Stream流

  • java.util.Stream 表示能应用在一组元素上一次执行的操作序列。
  • Stream 操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回 Stre am 本身,可以连续完成多个操作。

创建Stream

        Stream 的创建需要指定一个数据源

示例:

List<String> list = Arrays.asList("Basic", "QBasic","HTML", "c", "c++", "PowerBuilder","go", "Visual Basic", "c#","java");
Stream<String> stream = list.stream();
/**
* 返回一个串行流
*/
default Stream<E> stream()
/**
* 返回一个并行流
*/
default Stream<E> parallelStream()
/**
* 返回T的流
*/
public static<T> Stream<T> of(T t)
/**
* 返回其元素是指定值的顺序流。
*/
public static<T> Stream<T> of(T... values) {
     return Arrays.stream(values);
}
/**
* 过滤,返回由与给定predicate匹配的该流的元素组成的流
*/
Stream<T> filter(Predicate<? super T> predicate);
/**
* 此流的所有元素是否与提供的predicate匹配。
*/
boolean allMatch(Predicate<? super T> predicate)
/**
* 此流任意元素是否有与提供的predicate匹配。
*/
boolean anyMatch(Predicate<? super T> predicate);
/**
* 返回一个 Stream的构建器。
*/
public static<T> Builder<T> builder();
/**
* 使用 Collector对此流的元素进行归纳
*/
<R, A> R collect(Collector<? super T, A, R> collector);
/**
* 返回此流中的元素数。
*/
long count();
/**
* 返回由该流的不同元素(根据 Object.equals(Object) )组成的流。
*/
Stream<T> distinct();
/**
* 遍历
*/
void forEach(Consumer<? super T> action);
/**
* 用于获取指定数量的流,截短长度不能超过 maxSize 。
*/
Stream<T> limit(long maxSize);
/**
* 用于映射每个元素到对应的结果
*/
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
/**
* 根据提供的 Comparator进行排序。
*/
Stream<T> sorted(Comparator<? super T> comparator);
/**
* 在丢弃流的第n个元素后,返回由该流剩余元素组成的流。
*/
Stream<T> skip(long n);
/**
* 返回一个包含此流的元素的数组。
*/
Object[] toArray();
/**
* 使用提供的 generator函数返回一个包含此流的元素的数组,以分配返回的数组,以及区执行或调整大小可能需要的任何其他数组。
*/
<A> A[] toArray(IntFunction<A[]> generator);
/**
* 合并流
*/
public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)

4.1 Filter 过滤

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

示例:

List<String> strings = Arrays.asList("abc", "def", "gkh", "abc");

// 返回符合条件的stream流
// 计算流符合条件的stream流的数量
long count = strings.stream().filter(s -> "abc".equals(s)).count();
System.out.println(count)

4.2 Sorted 排序

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

示例:

List<String> strings = Arrays.asList("abc", "def", "gkh", "abc");

// 排序并遍历
strings.stream().sorted().forEach(System.out::println);

4.3 Map映射

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

List<String> strings = Arrays.asList("abc", "def", "gkh", "abc");
// 转换字符串为大写,降序后,输出
strings.stream()
 .map((item)->{return item.toUpperCase();})
 .sorted((s1,s2)->{return s2.compareTo(s1);})
 .forEach(System.out::println);

4.4 Match 匹配

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

示例:

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

		List<String> langList = Arrays.asList("Basic", "QBasic", "c", "C#", "c++", "PowerBuilder", "Visual Basic");

		String[] strs = { "双截棍", "龙卷风", "夜曲", "听妈妈的话" };

		// Arrays.stream 将数组转换为Stream对象
		Stream<String> stream = Arrays.stream(strs);

		boolean isStr = stream.anyMatch((str) -> {
			return str.length() == 2;
		});
		System.out.println(isStr);

		// 返回过滤后的数量
		long len = Arrays.stream(strs).filter((str) -> {
			return str.length() == 3;
		}).count();

		System.out.println(len);

//		// 任意一个符合
//		boolean isContains1 = langList.stream().anyMatch((lang) -> {
//			return lang.length() == 2;
//		});
//		System.out.println(isContains1);
//
//		// 所有元素均符合
//		boolean isContains2 = langList.stream().allMatch((lang) -> {
//			return lang.length() == 2;
//		});
//		System.out.println(isContains2);
//
//		// 所有元素都不符合
//		boolean isContains3 = langList.stream().noneMatch((lang) -> {
//			return lang.length() == 2;
//		});
//		System.out.println(isContains3);
	}
}

4.5 max最大值

public static void main(String[] args) {

		String[] strs = { "双截棍", "龙卷风", "夜曲", "听妈妈的话", "青花瓷", "青花瓷", "青花瓷", "双截棍", "稻香" };

		// 方式1 找出数组中长度最长的元素 去重 排序
		String str = Arrays.stream(strs).distinct().sorted((x, y) -> {
			if (x.length() == y.length()) {
				return x.compareTo(y);
			}
			return y.length() - x.length();
		}).findFirst().get(); // 查找第一个元素

		System.out.println(str);

		// 方式2 通过max获取
		String str1 = Arrays.stream(strs).distinct().max((x, y) -> {
			return x.length() - y.length();
		}).get();

		System.out.println(str1);
	}
}

4.6 Count计数

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

示例:

        // 返回过滤后的数量
		long len = Arrays.stream(strs).filter((str) -> {
			return str.length() == 3;
		}).count();

		System.out.println(len);

4.6 Collect 收集

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

将Stream中的元素,收集至新集合

  • Collectors.toList()
  • Collectors.toSet()
  • Collectors.toMap() 

示例:过滤Stream中的元素,并将过滤结果收集到一个新的集合(List、Set、Map)

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

		String[] strs = { "双截棍", "龙卷风", "夜曲", "听妈妈的话", "青花瓷", "青花瓷", "青花瓷", "双截棍", "稻香" };

		// 收集处理后的数据为一个List
		List<String> list = Arrays.stream(strs).distinct().collect(Collectors.toList());
		System.out.println(list);

		LinkedList<String> linkedlist = Arrays.stream(strs).distinct()
				.collect(Collectors.toCollection(LinkedList::new));
		System.out.println(linkedlist);
		// 收集处理后的数据为一个Set
		Set<String> set = Arrays.stream(strs).collect(Collectors.toSet());
		System.out.println(set);

		LinkedHashSet<String> LinkedHashset = Arrays.stream(strs).collect(Collectors.toCollection(LinkedHashSet::new));
		System.out.println(LinkedHashset);
	}
}
public class Test04 {
	public static void main(String[] args) {

		String[] strs = { "双截棍", "龙卷风", "夜曲", "听妈妈的话", "青花瓷", "青花瓷", "青花瓷", "双截棍", "稻香" };

		Stream<String> stream = Arrays.stream(strs);

//		Map<String, Integer> map1 = stream.distinct().collect(Collectors.toMap((str) -> {
//			return str;
//		}, (str) -> {
//			return str.length();
//		}));
//		System.out.println(map1);

		Map<String, Integer> map2 = stream.distinct().collect(Collectors.toMap(str -> str, str -> str.length()));
		System.out.println(map2);
	}
}

将Stream中的元素,映射后,收集至新集合:Collectors.mapping() 

示例:对Stream中的每个元素进行映射,并将映射结果收集到一个新的集合(List)

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

		List<String> list = Arrays.asList("12", "23", "34", "45", "56", "67");

		// 对Stream中的每个元素映射 并将新的结果收集到一个新的集合中
		List<Integer> numList = list.stream()
				.collect(Collectors.mapping(s -> Integer.parseInt(s) * 10, Collectors.toList()));

		System.out.println(list);
		System.out.println(numList);
	}
}

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

示例:对Stream中的每个元素进行分组统计,并将统计结果收集到一个新的集合(Map)

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

		List<String> nameList = Arrays.asList("李dcd", "曹植", "曹丕", "曹cd", "李qz", "张sw", "冯df", "冯rt", "梁lh", "梁家辉");

		// 分组
		Map<Character, List<String>> map = nameList.stream().collect(Collectors.groupingBy(s -> s.charAt(0)));
		System.out.println(map);
}

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

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

		List<String> nameList = Arrays.asList("李dcd", "曹植", "曹丕", "曹cd", "李qz", "张sw", "冯df", "冯rt", "梁lh", "梁家辉");

		// 按照判断规则 统计分区
		Map<Boolean, List<String>> map2 = nameList.stream().collect(Collectors.partitioningBy(s -> s.length() == 3));
		System.out.println(map2);
	}
}

4.7 Statistics 统计

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

示例:

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

		List<Integer> list = Arrays.asList(12, 34, 23, 56, 38, 34, 1);

		IntStream intStream = list.stream().mapToInt(x -> x);

		// 统计结果对象
		IntSummaryStatistics statistics = list.stream().mapToInt(x -> x).summaryStatistics();
		System.out.println("最大值:" + statistics.getMax());
		System.out.println("最小值:" + statistics.getMin());
		System.out.println("平均值:" + statistics.getAverage());
		System.out.println("和:" + statistics.getSum());
		System.out.println("个数:" + statistics.getCount());
	}
}

4.8 Parallel Streams 并行流

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

示例:排序

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

		int max = 1000000;
		List<String> number = new ArrayList<String>();
		for (int i = 0; i < max; i++) {
			number.add(UUID.randomUUID().toString());
		}

		long start = System.currentTimeMillis();
		// 串行
//		long count = number.stream().sorted().count();

		// 并行
		long count = number.parallelStream().sorted().count();

		long end = System.currentTimeMillis();

		System.out.println(end - start);
	}
}

函数式接口总结

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

五、日期时间

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

  • LocalDateTime:日期+时间 format: yyyy-MM-ddTHH:mm:ss.SSS
  • LocalDate:日期 format: yyyy-MM-dd
  • LocalTime:时间 format: HH:mm:ss

5.1 格式化

        LocalDate date1 = LocalDate.of(2021, 1, 26);
		LocalDate date2 = LocalDate.parse("2021-01-26");
		System.out.println(date1);
		System.out.println(date2);

		LocalDateTime dateTime1 = LocalDateTime.of(2021, 1, 26, 12, 12, 22);
		LocalDateTime dateTime2 = LocalDateTime.parse("2021-01-26T12:12:22");
		System.out.println(dateTime1);
		System.out.println(dateTime2);

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

5.2 字符串转日期格式

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

		LocalDate date = LocalDate.now();
		LocalTime time = LocalTime.now().withNano(0);
		LocalDateTime dateTime = LocalDateTime.now();

		System.out.println(date);
		System.out.println(time);
		System.out.println(dateTime);

		// 字符串转换为日期
		String str = "2023-08-17";
		date = LocalDate.parse(str);
		System.out.println(date);

		// 整数值转换为日期
		date = LocalDate.of(2023, 8, 17);
		System.out.println(date);

		// LocalDate --- 字符串

	}
}

5.3 日期计算

import java.time.LocalDate;
import java.time.Period;

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

		LocalDate now = LocalDate.now();
//		System.out.println(now.plus(10, ChronoUnit.DAYS));
//		System.out.println(now.plus(-10, ChronoUnit.DAYS));

		LocalDate date1 = LocalDate.parse("2002-01-17");
		LocalDate date2 = LocalDate.parse("2023-08-17");

		Period period = Period.between(date1, date2);
		System.out.println(period.getYears());
		System.out.println(period.getMonths());
		System.out.println(period.getDays());

		System.out.println(date2.toEpochDay() - date1.toEpochDay());

	}
}

5.4 获取指定日期

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;

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

		LocalDate now = LocalDate.now();

		LocalDate first = now.with(TemporalAdjusters.firstDayOfMonth());
		System.out.println(first);

		System.out.println(now.with(TemporalAdjusters.lastDayOfMonth()));

		System.out.println(now.with(TemporalAdjusters.lastDayOfYear()));

		System.out.println(now.with(TemporalAdjusters.lastDayOfMonth()).plusDays(1));

		System.out.println(now.with(TemporalAdjusters.lastInMonth(DayOfWeek.MONDAY)));
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农叮叮车

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值