Lambda 表达式

Java 8 引入的Lambda表达式是Java语言的一个重大革新,它极大地增强了Java对于函数式编程的支持。

Lambda表达式的引入使得代码更为简洁,函数式接口实现等方面带来了极大的便利。

Lambda语法

// 实现方法
(parameters) -> expression
或
(parameters) ->{ statements; }

// 传递方法或者构造函数引用(比如打印)
System.out::println

Lambda使用案例

  • 替代匿名内部类

// 以前
new Thread(new Runnable() {
	@Override
	public void run() {
		System.out.println("The runable now is using!");
	}
}).start();

//用lambda
new Thread(() -> System.out.println("It's a lambda function!")).start();
  • 迭代集合

List<String> strings = Arrays.asList("1", "2", "3");
// 以前
for (String s : strings) {
	System.out.println(s);
}

//Lambda foreach
strings.forEach((s) -> System.out.println(s));
//or
strings.forEach(System.out::println);

//map
Map<Integer, String> map = new HashMap<>();
map.forEach((k,v)->System.out.println(v));
  • 访问变量

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int i = 1;

// 可以访问外边变量i,但注意,外边变量在lambda中默认拥有final属性
// 不可以修改,如果修改,编译报错
numbers.forEach(n -> System.out.println(n - i));

Java Steam

Java 8 新增了java.util.stream包,它可以对集合数据进行排序,筛选,过滤等处理方式。

在代码中,一定程度上替代了以前对集合的for循环,让代码更加干净,简洁,高效。

它的源数据可以是 Collection、Array 等。由于它的方法参数都是函数式接口类型,所以一般和 Lambda 配合使用。

Steam语法

// steam的操作有三个步骤
// 1.创建Stream
// 2.中间操作:对数据进行处理
// 3.终止操作:一旦执行终止操作 ,就执行了中间操作链,并产生结果,之后就不会再被使用。这也是为什么说Stream是延迟执行的原因。
// 实际使用中常常将三个步骤合并一起执行
// 下面演示分开执行的步骤

// 创建数据源
List<String> strings = Arrays.asList("a", "b", "c", "d", "e");

// 步骤1:创建steam流
// 创建串行流
Stream<String> stream = strings.stream();
// 创建并行流(多线程执行,不常用)
Stream<String> parallelStream = strings.parallelStream()
// 数组创建(串行流)
String [] s = {"a" ,"b"};
Stream<String> stream= Arrays.stream(s);
// 还有其他创建流方法入Steam.of() 这里不再介绍

// 步骤2:中间操作
//中间操作符:
// 通过filter方法对集合中每个元素进行过滤
//filter
// 通过map方法对集合中每个元素进行操作
//map
// 排序
//sort
// 限制流,例如只取前流的前几个元素
//limit
// 跳过操作,例如跳过流的前几个元素
//skip
// 统计个数
//count
// 下面通过filter对集合进行过滤,过滤条件为 equals(a)
Stream<String> stringa = stream.filter(s -> s.equals("a"));

// 步骤3:终止符操作
// 终止操作符:
//收集操作,将所有数据收集起来,Stream 的核心在于Collectors,常用的Collectors.toSet()、Collectors.toList()、Collectors.groupingBy()。
//collect
//统计操作,统计最终的数据个数。
//count
//查找操作,查找第一个、查找任何一个 返回的类型为Optional。
//findFirst、findAny
//匹配操作,数据流中是否存在符合条件的元素 返回值为bool 值。
//noneMatch、allMatch、anyMatch
//最值操作,需要自定义比较器,返回数据流中最大最小的值。
//min、max
//规约操作,将整个数据流的值规约为一个值,count、min、max底层就是使用reduce。
//reduce
//遍历操作,这里就是对最终的数据进行消费了。
//forEach、forEachOrdered
//数组操作,将数据流的元素转换成数组。
//toArray

// 将中间操作之后的结果数据通过collect收集起来
// 通过Collectors.toList() 转换为一个List集合
List<String> collect = stringa.collect(Collectors.toList());

Steam使用案例

实际使用中常常会把stream的三个步骤合并在一起使用,这样使代码更加简洁。

// 数据源1:字符串集合
List<String> strings = Arrays.asList("a", "b", "c", "d", "e");
// 数据源2:LoginUser为用户信息对象
List<LoginUser> list = ...

// 过滤:找到不等于a的元素

List<String> collect = strings.stream().filter(item -> !"a".equals(item))
        .collect(Collectors.toList());


// map:获取用户集合的全部用户名
List<String> usernames = list.stream().map(LoginUser::getUsername)
        .collect(Collectors.toList());

// sort 排序:根据用户ID进行排序
//升序 默认
List<LoginUser> collect1 = list.stream().sorted(Comparator.comparing(LoginUser::getUserid))
        .collect(Collectors.toList());
// 降序 reversed()
List<LoginUser> collect2 = list.stream().sorted(Comparator.comparing(LoginUser::getUserid).reversed())
        .collect(Collectors.toList());

// sort排序:多字段排序 根据用户ID升序,登入时间降序
list.stream().sorted(Comparator.comparing(LoginUser::getUserid)
							.thenComparing(LoginUser::getLoginTime).reversed()
		)
        .collect(Collectors.toList());


// limit 取前三个元素
List<String> collect3 = strings.stream().limit(3)
        .collect(Collectors.toList());

// skip 跳过前三个元素
List<String> collect4 = strings.stream().skip(3)
        .collect(Collectors.toList());

// count 计算数量
long count1 = strings.stream().filter(item -> !"a".equals(item)).count();

Date-Time

这是对java.util.Date强有力的补充,解决了 Date 类的大部分痛点:

  • 非线程安全

  • 时区处理麻烦

  • 各种格式化、和时间计算繁琐

  • 设计有缺陷,Date 类同时包含日期和时间

java.time 主要类

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

格式化

// Date
Date now = new Date();
//format yyyy-MM-dd
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String date  = sdf.format(now);

//format HH:mm:ss
SimpleDateFormat sdft = new SimpleDateFormat("HH:mm:ss");
String time = sdft.format(now);

//format yyyy-MM-dd HH:mm:ss
SimpleDateFormat sdfdt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String datetime = sdfdt.format(now);

//---------------------------------------------------------------------------------
// Date Time
//format yyyy-MM-dd
LocalDate date = LocalDate.now();

//format HH:mm:ss
LocalTime time = LocalTime.now().withNano(0);

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

字符串日期转化

// Date
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date1 = sdf.parse("2021-01-26");

//---------------------------------------------------------------------------------
// Date Time
LocalDate date = LocalDate.of(2024, 3, 1);
LocalDate date = LocalDate.parse("2024-03-01");

LocalTime time = LocalTime.of(8, 20, 20);
LocalTime time = LocalTime.parse("08:20:20");

LocalDateTime dateTime = LocalDateTime.of(2024, 3, 1, 8, 20, 20);
LocalDateTime dateTime = LocalDateTime.parse("2024-03-01 08:20:20");

日期计算

// Date
//一周后的日期
SimpleDateFormat formatDate = new SimpleDateFormat("yyyy-MM-dd");
Calendar ca = Calendar.getInstance();
ca.add(Calendar.DATE, 7);
Date d = ca.getTime();
String after = formatDate.format(d);
System.out.println("一周后日期:" + after);

//算两个日期间隔多少天,计算间隔多少年,多少月方法类似
String dates1 = "2021-12-23";
String dates2 = "2021-02-26";
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date date1 = format.parse(dates1);
Date date2 = format.parse(dates2);
int day = (int) ((date1.getTime() - date2.getTime()) / (1000 * 3600 * 24));
System.out.println(dates1 + "和" + dates2 + "相差" + day + "天");
//结果:2021-02-26和2021-12-23相差300天

//---------------------------------------------------------------------------------
// Date Time
//一周后的日期
LocalDate localDate = LocalDate.now();
//方法1
LocalDate after = localDate.plus(1, ChronoUnit.WEEKS);
//方法2
LocalDate after2 = localDate.plusWeeks(1);
System.out.println("一周后日期:" + after);

//算两个日期间隔多少天,计算间隔多少年,多少月
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() + "天");
//打印结果是 “date1 到 date2 相隔:0年9月27天”
//这里period.getDays()得到的天是抛去年月以外的天数,并不是总天数
//如果要获取纯粹的总天数应该用下面的方法
long day = date2.toEpochDay() - date1.toEpochDay();
System.out.println(date1 + "和" + date2 + "相差" + day + "天");
//打印结果:2021-02-26和2021-12-23相差300天

获取指定日期

// Date
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
//获取当前月第一天:
Calendar c = Calendar.getInstance();
c.set(Calendar.DAY_OF_MONTH, 1);
String first = format.format(c.getTime());
System.out.println("first day:" + first);

//获取当前月最后一天
Calendar ca = Calendar.getInstance();
ca.set(Calendar.DAY_OF_MONTH, ca.getActualMaximum(Calendar.DAY_OF_MONTH));
String last = format.format(ca.getTime());
System.out.println("last day:" + last);

//当年最后一天
Calendar currCal = Calendar.getInstance();
Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.set(Calendar.YEAR, currCal.get(Calendar.YEAR));
calendar.roll(Calendar.DAY_OF_YEAR, -1);
Date time = calendar.getTime();
System.out.println("last day:" + format.format(time));

//---------------------------------------------------------------------------------
// Date Time
LocalDate today = LocalDate.now();
//获取当前月第一天:
LocalDate firstDayOfThisMonth = today.with(TemporalAdjusters.firstDayOfMonth());
// 取本月最后一天
LocalDate lastDayOfThisMonth = today.with(TemporalAdjusters.lastDayOfMonth());
//取下一天:
LocalDate nextDay = lastDayOfThisMonth.plusDays(1);
//当年最后一天
LocalDate lastday = today.with(TemporalAdjusters.lastDayOfYear());
//2021年最后一个周日,如果用Calendar是不得烦死。
LocalDate lastMondayOf2021 = LocalDate.parse("2021-12-31").with(TemporalAdjusters.lastInMonth(DayOfWeek.SUNDAY));