Stream流
/**
* 创建流
*/
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();// 顺序流
Stream<String> parallelStream = list.parallelStream();// 并行流
Stream<Integer> stream2 = Stream.iterate(0, x -> x + 2).limit(6);
stream2.forEach(System.err::println);
//将文件每一行内容转换成流
BufferedReader reader = new BufferedReader(new FileReader("D:\\test\\stream_text.txt"));
Stream<String> lineStream = reader.lines();
lineStream.forEach(System.out::println);
/**
* 流的方法:
*
* filter
* limit(n) 获取n个元素
* skip(n) 跳过n个元素 与limit(n)可以实现分页
* distinct 过滤重复的元素 使用equls和hashCode
*
*/
Optional
User user = new User("1", "name", "password");
/**
* 获取 Optional对象
*
* static <T> Optional<T> empty()返回空的 Optional 实例
* static <T> Optional<T> of(T value) 返回一个指定非null值的Optional。
* static <T> Optional<T> ofNullable(T value) 如果为非空,返回 Optional 描述的指定值,否则返回空的Optional
*/
Optional<User> empOptional = Optional.empty();
Optional<User> ofoOptional = Optional.of(user);
Optional<User> ofnullOptional = Optional.ofNullable(user);
/**
* Optional<T> filter(Predicate<? super <T> predicate)
* 如果值存在,并且这个值匹配给定的 predicate(断言),返回一个Optional用以描述这个值,否则返回一个空的Optional。
*/
ofnullOptional.filter(u -> u.getId().equals("1"));
/**
* <U> Optional<U> flatMap(Function<? super T,Optional<U>> mapper)
* 如果值存在,返回基于Optional包含的映射方法的值,否则返回一个空的Optional
*/
ofnullOptional.flatMap(u -> Optional.ofNullable(u.getPassword()));
/**
* <U>Optional<U> map(Function<? super T,? extends U> mapper)
* 如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional。
*/
ofnullOptional.map(u -> u.getPassword());
/**
* T get() 如果在这个Optional中包含这个值,返回值,否则抛出异常:NoSuchElementException
*/
ofnullOptional.get();
/**
* int hashCode() 返回存在值的哈希码,如果值不存在 返回 0。
*/
ofnullOptional.hashCode();
/**
* void ifPresent(Consumer<? super T> consumer) 如果值存在则使用该值调用 consumer(消费函数),否则不做任何事情。
*/
ofnullOptional.ifPresent(u -> {
System.out.println("逻辑代码");
});
/**
* boolean isPresent() 如果值存在则方法会返回true,否则返回 false。
*/
ofnullOptional.isPresent();
/**
* T orElse(T other) 如果存在该值,返回值, 否则返回 other。
*/
ofnullOptional.orElse(new User("2","name","pwd"));
/**
* T orElseGet(Supplier<? extends T> other) 如果存在该值,返回值, 否则触发 other,并返回 other 调用的结果。
*/
ofnullOptional.orElseGet(() ->{
System.err.println("orElseGet");
return new User("3","name","pwd");
});
/**
* <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier)
* 如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常
*/
ofnullOptional.orElseThrow(() -> new NullPointerException("user为空"));
//Demo
ofnullOptional.filter(u -> u.getId().equals("1")).ifPresent(u -> {System.err.println(u.getPassword());});
Lambda 表达式
Lambda 表达式,也可称为闭包,Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
语法
(parameters) -> expression
或
(parameters) ->{ statements; }
以下是lambda表达式的重要特征:
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
- 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
- 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
- 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定表达式返回了一个数值。
Lambda实列
@Test
public void LambdaTest() {
LambdaTest test = (a, b) -> a + b;
System.err.println(test.sum(10, 15));
methodTest((a, b) -> {
return a * b;
});
Consumer consumer = msg -> System.err.println(msg);
consumer.message("Hello Message");
}
interface LambdaTest {
int sum(int a, int b);
}
interface Consumer {
void message(String msg);
}
public void methodTest(LambdaTest test) {
System.err.println(test.sum(10, 20));
}
变量作用域
不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误
@Test
public void LambdaTest() {
int num = 3;
methodTest((a, b) -> {
//编译错误
num = 10;
return a * num;
});
}
public void methodTest(LambdaTest test) {
System.err.println(test.sum(10, 20));
}
interface LambdaTest {
int sum(int a, int b);
}
方法引用
方法引用需要使用函数接口
@FunctionalInterface
public interface Supplier<T> {
T get();
}
@Test
void methodTest() {
User user = create(User::new);
}
public static User create(Supplier<User> supplier) {
return supplier.get();
}
函数式接口
函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
函数式接口可以被隐式转换为 lambda 表达式。
Lambda 表达式和方法引用(实际上也可认为是Lambda表达式)上。
@Test
void functionIntface() {
/**
* 接受一个输入参数,返回一个布尔值结果
*/
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
Predicate<Integer> predicate = n -> true;
predicate = predicate.and(n -> n > 5).or(n -> n == 1);
functionTest(list, predicate);
/**
* 接受一个参数为类型T,返回值类型也为T。
*/
UnaryOperator<Integer> unaryOperator = n -> {
return n + 100;
};
System.err.println(unaryOperator.apply(100));
/**
* 代表了一个接受两个输入参数的操作,并且不返回任何结果
*/
BiConsumer<String, String> biConsumer = (n, n2) -> {
System.err.println(n + n2);
};
biConsumer.accept("Hello", " BiConsumer");
/**
* 代表了boolean值结果的提供方
*/
booleanSupplier(() -> false);
}
public void functionTest(List<Integer> list, Predicate<Integer> predicate) {
for (Integer i : list) {
if (predicate.test(i)) {
System.err.println(i);
}
}
}
public void booleanSupplier(BooleanSupplier booleanSupplier) {
System.err.println(booleanSupplier.getAsBoolean());
}
默认方法
Java 8 新增了接口的默认方法。
简单说,默认方法就是接口可以有实现方法,而且不需要实现类去实现其方法。
我们只需在方法名前面加个 default 关键字即可实现默认方法
为什么要有这个特性?
首先,之前的接口是个双刃剑,好处是面向抽象而不是面向具体编程,缺陷是,当需要修改接口时候,需要修改全部实现该接口的类,目前的 java 8 之前的集合框架没有 foreach 方法,通常能想到的解决办法是在JDK里给相关的接口添加新的方法及实现。然而,对于已经发布的版本,是没法在给接口添加新方法的同时不影响已有的实现。所以引进的默认方法。他们的目的是为了解决接口的修改与现有的实现不兼容的问题。
语法
public interface Vehicle {
default void print(){
System.out.println("我是一辆车!");
}
}
日期时间 API
@Test
public void localDateTest() {
LocalDateTime currentTime = LocalDateTime.now();
System.err.println("当前时间:" + currentTime);
System.err.println(currentTime.toLocalDate());
System.err.println(currentTime.toLocalTime());
Month month = currentTime.getMonth();
int day = currentTime.getDayOfMonth();
int seconds = currentTime.getSecond();
System.err.println("月: " + month + ", 日: " + day + ", 秒: " + seconds);
LocalDateTime date2 = currentTime.withDayOfMonth(10).withYear(2012);
System.err.println(date2);
// 解析字符串
LocalTime date5 = LocalTime.parse("20:15:30");
System.err.println("date5: " + date5);
// 22 小时 15 分钟
LocalTime date4 = LocalTime.of(22, 15);
System.err.println("date4: " + date4);
// 12 december 2014
LocalDate date3 = LocalDate.of(2014, Month.DECEMBER, 12);
System.err.println("date3: " + date3);
System.out.println("========================带时区的时间======================");
/**
* 获取当前时间日期
*/
ZonedDateTime date1 = ZonedDateTime.parse("2015-12-03T10:15:30+05:30[Asia/Shanghai]");
System.err.println("date1: " + date1);
ZoneId id = ZoneId.of("Europe/Paris");
System.err.println("ZoneId: " + id);
ZoneId currentZone = ZoneId.systemDefault();
System.err.println("当期时区: " + currentZone);
}
运行结果
当前时间:2022-08-15T17:32:45.081
2022-08-15
17:32:45.081
月: AUGUST, 日: 15, 秒: 45
2012-08-10T17:32:45.081
date5: 20:15:30
date4: 22:15
date3: 2014-12-12
date1: 2015-12-03T10:15:30+08:00[Asia/Shanghai]
ZoneId: Europe/Paris
当期时区: Asia/Shanghai
Java8核心特性:Stream、Optional与Lambda表达式解析
1107

被折叠的 条评论
为什么被折叠?



