Java8特性

目录

前言

interface接口的新特性 

Lambda表达式

函数式接口(Funcation Interface)

使用Lambda表达式实现函数式接口:

示例2:迭代

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

Predicate接口

Function

Comparator

Stream流

(1)创建一个Stream流 

(2)常用方法

(3)Filter过滤器

(4)Sorted 排序

(5)Map 映射

(6)Match 匹配

 (7)Count 计数

(8)Collect 收集

(9)Statistics 统计

(10)Parallel Streams 并行流

函数式接口总结

日期时间   

格式化 

字符串转日期格式

日期计算

获取指定日期


前言

        Java8作为java发布一来改动最大的版本,主要添加了stream流,函数式接口,一些时间日期类,也是目前比较稳定的版本,很多项目都还在使用这个版本


interface接口的新特性

        在interface接口中不但可以使用abstratct抽象方法,还可以定义default默认方法与static静态方法。

        default方法:修饰方法后,该方法属于实例方法,可以被实现类调用或者重写。

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

重写:实现类implements不同接口时,接口中存在相同的方法签名(方法名,参数,返回值类型)的方法,必须重写该方法。

        static静态方法:修饰的方法属于静态方法,不能被子类继承,只能通过实现接口调用。


Lambda表达式

        Java8中引入了一个新的语法元素和操作符。这个操作符为”->“,该操作符为Lambda操作符(箭头操作符)。

        Lambda表达式需要的参数列表    ->      Lambda体,为抽象方法的实现逻辑

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

无参实例:

        当我们要创建一个Method实例时,如果我们只使用一次,通常会采用匿名实现类的方式来实现,代码相对多。这个时候我们就可以使用Lambda表达式,来使代码更加简练。(这种编程风格也叫做函数式编程风格)。箭头右侧就是匿名实现类的具体实现。

public class Test01{
    public static void main(String[] args) {
        Method method = () -> System.out.println("!");
       /**替代了以下代码
         *      Method method = new Method() {
         *             @Override
         *             public void dosth() {
         *                 System.out.println("1");
         *             }
         *         };
         */
        method.dosth1();
    }
}

interface Method{
    public void dosth1();
}

有参实例: 

        当method接口中有抽象方法,且有返回值,有两个参数,。可以使用Lambda表达式减少代码量。

public class Test01{
    public static void main(String[] args) {
        //在Lambda表达式中处理两个参数,具体实现功能。
        Method method = (x1,x2) -> x1+x2;
        /**替代了以下代码
         * Method method1 = new Method() {
         *             @Override
         *             public int add(int x1, int x2) {
         *                 return x1+x2;
         *             }
         *         };
         */
        
        
        //用创建的实例对象,调用add方法
        System.out.println(method.add(10,10));
    }
}

interface Method{
    public int add(int x1 , int x2);
}

Lambda表达式的本质:函数式接口的实现类。


函数式接口(Funcation Interface)

        定义只包含一个抽象方法的接口我们称为函数式接口。可以使用@Functioninterface注解来强化语义规范,也被称为SAM接口(single Abstract Method Interfaces)。

使用Lambda表达式实现函数式接口:

1.示例一:排序

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

示例2:迭代

List<String> langList = Arrays.asList("Basic","QBasic","c","c++","PowerBuilder","Visual Basic");
		
langList.forEach((name)->{
    System.out.println(name);
});

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

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

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

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

Comparator

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

// 案例数据
List<String> langList = Arrays.asList("Basic", "QBasic","HTML", "c", "c++", "PowerBuilder", "go", "Visual Basic", "c#","java");

// 按照ASCII码比较
Comparator<String> comparator1 = (s1, s2) -> {
    return s1.compareTo(s2);
};

// 按照长度比较
Comparator<String> comparator2 = (s1, s2) -> {
    return s1.length() - s2.length();
};

// 先比较长度,再比较ASCII码
Comparator<String> comparator3 = comparator2.thenComparing(comparator1);

// 在comparator3的基础上,反转条件
Comparator<String> comparator4 = comparator2.reversed();

// 按照指定Comparator,进行排序
langList.sort(comparator2);

Stream流​​​​​​​

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

(1)创建一个Stream流 

        List<String> list = Arrays.asList("A", "B", "C", "D", "E", "F", "G");
        Stream stream = list.stream();

(2)常用方法

/**
* 返回一个串行流
*/
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)

(3)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)Sorted 排序

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

List<String> strings = Arrays.asList("abc", "def", "gkh", "abc");
	    
// 排序并遍历
strings.stream()
        .sorted()
        .forEach(System.out::println);

(5)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);

(6)Match 匹配

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

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

// 整体匹配
boolean isMatch1 = strings.stream().allMatch((s) -> s.length() == 3);
System.out.println(isMatch1); // false

// 局部匹配
boolean isMatch2 = strings.stream().anyMatch((s) -> s.length() == 3);
System.out.println(isMatch2); // true

 (7)Count 计数

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

List<String> strings = Arrays.asList("abc", "deft", "gkh", "abc");
		
// 统计“a”开头的元素个数
long count = strings.stream().filter((s)->s.startsWith("a")).count();
System.out.println(count);

(8)Collect 收集

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

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

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

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

// 将过滤结果,收集至List集合,默认为ArrayList
List<String> resultList = langList.stream()
                                .filter(s->s.toUpperCase().contains("B"))
                                .collect(Collectors.toList());
System.out.println(resultList);

// 将过滤结果,收集至LinkedList集合
LinkedList<String> resultLinkedList = langList.stream()
                                                .filter(s->s.toUpperCase().contains("B"))
                                                .collect(Collectors.toCollection(LinkedList::new));
System.out.println(resultLinkedList);

// 将过滤结果,收集至Set集合,默认为HashSet
Set<String> resultSet = langList.stream()
                                .filter(s->s.toUpperCase().contains("B"))
                                .collect(Collectors.toSet());

// 将过滤结果,收集至Map集合,默认为HashMap
Map<String,Integer> resultMap = langList.stream()
                                        .filter(s->s.toUpperCase().contains("B"))
                                        .collect(Collectors.toMap(s->s, s->s.length()));
System.out.println(resultMap);

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

Collectors.mapping()

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

// 将字符串集合中的每个字符串,映射转换为Integer
List<String> numberStrings = Arrays.asList("4344","6641","3432","6432","6423","9423");
List<Integer> numberList = numberStrings.stream()
    								.collect(Collectors.mapping(s->Integer.parseInt(s), Collectors.toList()));
System.out.println(numberList);

将Stream中的元素,分组后,收集至Map集合

Collectors.groupingBy()

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

// 按照字符数统计
Map<Integer,List<String>> resultMap1 = langList.stream()
    										.collect(Collectors.groupingBy(s->s.length()));
System.out.println(resultMap1);
		
// 按照首字母统计
Map<Character,List<String>> resultMap2 = langList.stream()
    										.collect(Collectors.groupingBy(s-               >s.toLowerCase().charAt(0)));
System.out.println(resultMap2);

将Stream中的元素,按照判断规则,统计分区后,收集至Map集合

Collectors.partitioningBy()

// 按照内容中是否包含"b"或"c",将原集合统计分区后,形成两个分区,并存入Map集合
Map<Boolean,List<String>> resultMap = langList.stream()
    .collect(Collectors.partitioningBy(s->s.toLowerCase().contains("b")||s.toLowerCase().contains("c")));
System.out.println(resultMap);

(9)Statistics 统计

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

List<Integer> number = Arrays.asList(1, 2, 5, 4);

IntSummaryStatistics statistics = number.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());

(10)Parallel Streams 并行流

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

示例:排序

准备示例数据

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

串行排序

long t0 = System.nanoTime(); 
long count = values.stream().sorted().count(); System.out.println(count); 
long t1 = System.nanoTime(); long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0); System.out.println(String.format("串行排序,耗时共计: %d 毫秒", millis));

串行排序,耗时共计591毫秒

并行排序

long t0 = System.nanoTime(); long count = values.parallelStream().sorted().count();
 System.out.println(count); long t1 = System.nanoTime();
 long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0); System.out.println(String.format("并行排序,耗时共计: %d 毫秒", millis));

并行排序,耗时共计283毫秒

函数式接口总结

  1. PredicateFunctionConsumerComparator
  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

格式化 

 //Format yyyy-MM-dd
LocalDate date = LocalDate.now();
System.out.println(String.format("Date format : %s", date));

//Format HH:mm:ss
LocalTime time = LocalTime.now().withNano(0);
System.out.println(String.format("Time format : %s", time));

//Format yyyy-MM-dd HH:mm:ss
LocalDateTime dateTime = LocalDateTime.now();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String dateTimeStr = dateTime.format(dateTimeFormatter);
System.out.println(String.format("DateTime Format : %s", dateTimeStr));

字符串转日期格式

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

日期计算

// 计算一周后的日期
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("2021-02-26");
LocalDate date2 = LocalDate.parse("2021-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 + "天");

获取指定日期

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

#0000FF格子衫

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

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

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

打赏作者

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

抵扣说明:

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

余额充值