个人总结java8实用经验有需取用

PS:Lambda表达式即为内部类实现的简写形式。可理解为专注于业务的编写,忽略繁琐的类名、方法名的约束。但是也一定意义上降低代码所传递的信息量。

Lambda表达式

Lambda需要使用一种新的语法元素和操作符,这个操作符为“->”,所以也叫箭头函数,这个操作符称为Lambda操作符。这个操作符将Lambda分为了两个部分

箭头左侧:指定了Lambda表法式需要的参数列表

箭头右侧:指定了Lambda体,是抽象方法的实现逻辑,也就是我们最需要关心的地方

准备工作:为了更好演示Lambda表达式,先给出5个接口,分别对应:无参无返回值,一个参数无返回值,两个参数(多个)无返回值,无参有返回值,一个参数有返回值

public interface NoReturnNoParam {
    void method();
}
public interface NoReturnOneParam {
    void method(int a);
}
public interface NoReturnMutilParam {
    void method(int a , int b);
}
public interface ReturnNoParam {
    int method();
}
public interface ReturnOneParam {
    int method(int a);
}
 @Test
    public void Test(){
        Lambda语法一:无参无返回值

        NoReturnNoParam nrnp = () -> { System.out.println("method方法执行了"); };
        nrnp.method();

        Lambda语法二:一个参数无返回值

        NoReturnOneParam nrop = (int a) -> { System.out.println(a + "\tmethod方法执行了"); };
        nrop.method(1);
				//也可以省略参数类型
        NoReturnOneParam nrop = (a) -> { System.out.println(a + "\tmethod方法执行了"); };
        nrop.method(1);
				//接着 可以把小括号去掉
        NoReturnOneParam nrop = a -> { System.out.println(a + "\tmethod方法执行了"); };
        nrop.method(1);
				//在Lambda体中只有一条语句,可以省略大括号
        NoReturnOneParam nrop = a -> System.out.println(a + "\tmethod方法执行了");
        nrop.method(1);

        Lambda语法三:多个参数无返回值

        NoReturnMutilParam nrmp = (int a , int b) -> { System.out.println(a + b + "\tmethod方法执行了"); };
        nrmp.method(1, 2);
				//可以省略参数类型
        NoReturnMutilParam nrmp = (a , b) -> { System.out.println(a + b + "\tmethod方法执行了"); };
        nrmp.method(1, 2);
        //这里就不能省略括号了,因为有两个参数
				//在Lambda体中只有一条语句,可以省略大括号
				
        Lambda语法四:无参有返回值

        ReturnNoParam rnp = () -> {return 1;};
        System.out.println(rnp.method());
        //Lambda体中只有一条语句,可以省略return与大括号
        ReturnNoParam rnp = () -> 1;
        System.out.println(rnp.method());


    }

函数式接口

使用的众多方法的形参中即为Function<T,R>最为常见

函数式接口参数类型返回类型抽象方法用途
Consumer消费型接口Tvoidvoid accept(T t)对类型为T的对象应用操作
Supplier供给型接口TT get()返回类型为T的对象
Function<T,R>函数型接口TRR apply(T t)对类型为T的对象应用操作,并返回结果,结果是R类型的对象
Predicate 断定型接口Tbooleanboolean test(T t)确定类型为T的对象是否满足约束条件
 Consumer是消费型接口,有一个参数无返回类型,意味你给我东西消费

    public static void main(String[] args) {
        happyTime(100, money -> System.out.println("我消费了" + money));
    }

    public static void happyTime(double money, Consumer<Double> con){
        con.accept(money);
    }

    public static void main(String[] args) {
        List<String> list1 = Arrays.asList("天津", "北京", "南京", "东京", "西京");
        List<String> list = filterString(list1, str -> str.contains("京"));
        System.out.println(list);
    }

    public static List<String> filterString(List<String> list, Predicate<String> pred){
        List<String> res = new ArrayList<>();
        for(String str : list){
            if(pred.test(str)){
                res.add(str);
            }
        }
        return res;
    }

Stream API(集合Lamba表达式与函数式接口与一身的使用实例)

Stream API的概述:

1)Java 8中有两大最重要的改变。第一个是Lambda表达式:另一个则是Stream API。

2)Stream API(java.util.stream)把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充,因为Stream API可以极大提供Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

3)Stream关注的是对数据的运算,与CPU打交道,集合关注的是数据的存储,与内存打交道。

为什么使用Stream API:

Stream和Collection集合的区别:Collection是一种静态的内存数据结构,而Stream是有关计算的。前者是主要面向内存,存储在内存中,后者主要是面向CPU,通过CPU实现计算。

Stream的理解:

    Stream是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。“集合讲的是数据,Stream讲的是计算”。

注意:

1)Stream自己不会存储元素。

2)Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream。

Integer[] integers = new Integer[]{1,2,3,4,5};
List<Integer> collect = Arrays.stream(integers).filter(e -> e.equals(1)).collect(Collectors.toList());
System.out.println(Arrays.asList(integers));
System.out.println(collect);

3)Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

Stream操作的三个步骤:

1)创建Stream:一个数据源(如:集合数组),获取一个流,Stream的实例化

2)中间操作:一个中间操作链,对数据源的数据进行处理(如:过滤、映射等)

3)终止操作(终端操作):一旦执行终止操作,就执行中间操作链,并产生结果。之后,就不会再被使用。

1-筛选与切片

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

2-映射

方法描述
map(Function f)接收上一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
mapToDouble(ToDoubleFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的DoubleStream
mapToInt(ToIntFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的IntStream
mapToLong(ToLongFunction f)接受一个函数作为参数,该函数会被应用到每个元素上,产生一个新的LongStream

3-排序

方法描述
sorted()产生一个新流,其中按自然顺序排序
sorted(Comparator com)产生一个新流,其中按比例器顺序排序

Stream的终止操作:
1)终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer。甚至是void。

2)流进行了终止操作后,不能再次使用。

1-匹配与查找

方法描述
allMatch(Predicate p)检查是否匹配所有元素
anyMatch(Predicate p)检查是否至少匹配一个元素
noneMatch(Predicate p)检查是否没有匹配所有元素
findFirst()返回第一个元素
findAny()返回当前流中的任意元素
count()返回流中元素总数
max(Comparator c)返回流中最大值
min(Comparator c)返回流中最小值
forEach(Consumer c)内部迭代(使用Collection接口需要用户去做迭代,称为外部迭代。相反,Stream API使用内部迭代——它帮你把迭代做了)。

其中forEach()中使用return,返回到stream流当行继续执行后续业务代码,手写for循环中出现return,直接返回方法调用处,后续业务代码不会执行,可利用此特性根据业务需求进行适当使用。
2-归约

方法描述
reduce(T iden,BinaryOperator b)可以将流中元素反复结合起来,得到一个值。返回T
reduce(BinaryOperator b)可以将流中元素反复结合起来,得到一个值。返回Optional

备注:map和reduce的连接通常称为map-reduce模式,因Google用它来进行网络搜索而出名。

3-收集

方法描述
collect(Collector c)将流转换成其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法。

​ Collector接口中方法的实现决定了如何对流执行收集的操作(如收集到List、Set、Map)。

    另外,Collectors实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:
方法返回类型作用
toListList把流中元素收集到List
List emps=list.stream().collect(Collectors.toList());
toSetSet把流中元素收集到Set
Set emps=list.stream().collect(Collectors.toSet());
toCollectiomCollection把流中元素收集到创建地集合
Collection emps=listt.stream().collect(Collectors.toCollection(ArrayList::new))
countingLong计算流中元素的个数
long count=list.stream().collect(Collectors.counting());
summingIntInteger对流中元素的整数属性求和
int total=list.stream().collect(Collectors.summingInt(Employee::getSalary));
averagingIntDouble计算流中元素Integer属性的平均值
double avg=list.stream().collect(Collectors.averagingInt(Employee::getSalary));
summarizingIntIntSummaryStatistics收集流流中Integer属性的统计值。如:平均值
int SummaryStatisticsis=list.stream().collect(Collectors.summarizingInt(Employee::getSalary));
public class StreamToMapTest {
    public static void main(String[] args) {
        List<User> users = new ArrayList<>();
        User user1 = new User(1, "1");
        User user2 = new User(2, "2");
        User user3 = new User(3, "3");
        users.add(user1);
        users.add(user2);
        users.add(user3);
        // 将id属性读取出来组成list
        List<Integer> idList = users.stream().map(User::getId).collect(Collectors.toList());
        System.out.println(idList);

        // 将id属性读取出来组成list 并去重
        List<Integer> idList2 = users.stream().map(User::getId).distinct().collect(Collectors.toList());
        System.out.println(idList2);

        // 组装成map
        Map<Integer, String> mp1 = users.stream().collect(Collectors.toMap(User::getId, User::getName));
        System.out.println(mp1);

        User user3_1 = new User(3, "3-1");
        users.add(user3_1);

        // 组装成map
        // key 重复会报错
        // Map<Integer, String> mp2 = users.stream().collect(Collectors.toMap(User::getId, User::getName));
        // System.out.println(mp1);

        // 组装成map 值取前面的
        Map<Integer, String> mp3 = users.stream().collect(Collectors.toMap(User::getId, User::getName, (v1, v2) -> v1));
        System.out.println(mp3);

        // 组装成map 值取后面的
        Map<Integer, String> mp2 = users.stream().collect(Collectors.toMap(User::getId, User::getName, (v1, v2) -> v2));
        System.out.println(mp2);

        // 组装成map 值取累加
        Map<Integer, String> mp4 = users.stream().collect(Collectors.toMap(User::getId, User::getName, (v1, v2) -> v1+v2));
        System.out.println(mp4);

        // 根据id 组装list对象,对应id的对象成组
        Map<Integer, List<User>> mp5 = users.stream().collect(Collectors.groupingBy(User::getId));
        System.out.println(mp5);

        // 根据id 组装list对象,对应id的对象的某个属性成组
        Map<Integer,List<String>> mp6 = users.stream().collect(Collectors.groupingBy(User::getId, Collectors.mapping(User::getName, Collectors.toList())));
        System.out.println(mp6);

        Map<Integer, List<String>> mp7 = users.stream().collect(Collectors.toMap(User::getId,
                p ->  {
                    List<String> getNameList = new ArrayList<>();
                    getNameList.add(p.getName());
                    return getNameList;
                },
                (List<String> value1, List<String> value2) -> {
                    value1.addAll(value2);
                    return value1;
                }
        ));
        System.out.println(mp7);

        User user4 = new User(4, null);
        users.add(user4);

        // 属性为空值,也可以输出
        Map<Integer, List<String>> mp8 = users.stream().collect(Collectors.toMap(User::getId,
                p ->  {
                    List<String> getNameList = new ArrayList<>();
                    getNameList.add(p.getName());
                    return getNameList;
                },
                (List<String> value1, List<String> value2) -> {
                    value1.addAll(value2);
                    return value1;
                }
        ));
        System.out.println(mp8);

        // 以对象为值
        Map<Integer, User> mp9 = users.stream()
                .filter(distinctByKey(User::getId))
                .collect(Collectors.toMap(User::getId, User -> User));
        System.out.println(mp9);
    }

    public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object,Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }
}

class User{
    private Integer id;
    private String name;

    public User() {
    }

    public User(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Optional类:

Optional类简介:
1)到目前为止,空指针异常是导致Java应用程序失败的最常见原因。以前,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类,Guava通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代码。受到Google Guava的启发,Optional类已经成为Java 8类库的一部分。

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

3)Optional类的Javadoc描述如下:这是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true。调用get()方法返回该对象。

Optional方法:
1)Optional提供很多有用的方法,这样就不用显式进行空值检测。

2)创建Optional类对象的方法:
Optional.of(T t):创建一个Optional实例,t必须非空

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

    Optional.ofNullable(T t):t可以为null

3)判断Optional容器中是否包含对象:

    boolean isPresent():判断是否包含对象

    void ifPresent(Consumer<? super T> consumer):如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它。

4)获取Optional容器的对象:

    T get():如果调用对象包含值,返回该值,否则抛异常

    T orElse(T other):如果有值则将其返回,否则返回指定的other对象

    T orElseGet(Supplier<? extends T> other):如果有值则将其返回,否则返回由Supplier接口实现提供的对象

    T orElseThrow(Supplier<? extends X> exceptionSupplier):如果有值则将其返回,否则抛出由Supplier接口实现提供的异常

ps:orElse与orElseGet的区别:

下例中Line 3的asList方法不管collect是否为null,均会执行。倘若是耗时操作或者是对类文件及数据有改动的操作,需使用orElseGet,传入内部类,实现方法,即可保证collect不为null时,asList不执行。

        Integer[] integers = new Integer[]{1,2,3,4,5};
        List<Integer> collect = Arrays.stream(integers).filter(e -> e.equals(1)).collect(Collectors.toList());
        Optional.of(collect).orElse(Arrays.asList(integers));
        Optional.ofNullable(collect).orElseGet(new Supplier<List<Integer>>() {
            @Override
            public List<Integer> get() {
                return Arrays.asList(integers);
            }
        });

日期

jak8主要提供了3个类用于处理时间和日期(其实还有不少,这3个类最为常见)

LocalDate:表示一个具体的日期,但是不包含具体的时间,也不包含时区信息
LocalTime:表示一个具有的时间,但是不包含日期信息
LocalDateTime:是LocalDateLocalTime的结合体

LocalDate

LocalDate date = LocalDate.of(2020, 1, 29);
int year = date.getYear();
Month month = date.getMonth();
int dayOfMonth = date.getDayOfMonth();
DayOfWeek dayOfWeek = date.getDayOfWeek();     // 一周的第几天
int length = date.lengthOfMonth();             // 月份的天数
boolean leapYear = date.isLeapYear();          // 是否为闰年
//获取当前日期
LocalDate now = LocalDate.now();

LocalTime

LocalTime localTime = LocalTime.of(17, 23, 52);     // 初始化一个时间:17:23:52
int hour = localTime.getHour();                     // 时:17
int minute = localTime.getMinute();                 // 分:23
int second = localTime.getSecond();                 // 秒:52

LocalDateTime

LocalDateTime ldt1 = LocalDateTime.of(2017, Month.JANUARY, 4, 17, 23, 52);

LocalDate localDate = LocalDate.of(2017, Month.JANUARY, 4);
LocalTime localTime = LocalTime.of(17, 23, 52);
LocalDateTime ldt2 = localDate.atTime(localTime);

日期格式化

LocalDateTime dateTime = LocalDateTime.now();
String strDate1 = dateTime.format(DateTimeFormatter.BASIC_ISO_DATE);    // 20170105
String strDate2 = dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE);    // 2017-01-05
String strDate3 = dateTime.format(DateTimeFormatter.ISO_LOCAL_TIME);    // 14:20:16.998
String strDate4 = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));   // 2017-01-05
String strDate5 = dateTime.format(DateTimeFormatter.ofPattern("今天是:YYYY年 MMMM DD日 E", Locale.CHINESE)); // 今天是:2017年 一月 05日 星期四
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值