Java语法新特性-函数接口、Stream、Option
1.四大函数接口
public class FunctionInterfaceDemo {
public static void main(String[] args) {
test04();
}
/**
* Supplier 没有入参,有出参
*/
public static void test04() {
Supplier<Integer> supplier1 = new Supplier<Integer>() {
@Override
public Integer get() {
System.out.println(10);
return 10;
}
};
System.out.println(supplier1.get());
Supplier<Integer> supplier2 = () -> {
System.out.println(11);
return 11;
};
System.out.println(supplier2.get());
}
/**
* Consumer 有入参,没有返回值
*/
public static void test03() {
// Consumer<Integer>,消费型接口,只有输入,没有返回值。
Consumer<Integer> consumer1 = new Consumer<Integer>() {
@Override
public void accept(Integer integer) {
System.out.println(integer);
}
};
consumer1.accept(10);
Consumer<Integer> consumer2 = v -> System.out.print(v + 1);
Consumer<Integer> consumer3 = System.out::println;
consumer2.accept(11);
}
/**
* Predicate 预言
*/
public static void test02() {
// Predicate<Integer>,泛型Integer为输入类型,Predicate为对输入值操作后的布尔值。
Predicate<Integer> predicate1 = new Predicate<Integer>() {
@Override
public boolean test(Integer integer) {
return integer > 0;
}
};
System.out.println(predicate1.test(10));
Predicate<Integer> predicate2 = v -> v > 0;
System.out.println(predicate2.test(10));
}
/**
* Function 有入参,有出参
*/
public static void test01() {
// Function<String, String>,第一个泛型是输入值,第二个泛型是输出值
Function<String, String> function1 = new Function<String, String>() {
@Override
public String apply(String s) {
return s + s;
}
};
System.out.println(function1.apply("tom")); // tomtom
// lambda
Function<String, String> function2 = s -> s + s + s;
System.out.println(function2.apply("bob")); // bobbobbob
}
}
2.Stream
public class StreamDemo {
public static void main(String[] args) {
User user1 = new User(1, "tom1", 11, "t1");
User user2 = new User(2, "tom2", 12, "t2");
User user3 = new User(3, "tom3", 13, "t3");
User user4 = new User(4, "tom4", 14, "t4");
User user5 = new User(5, "tom4", 15, "t4");
// List用于数据存储
List<User> users = new ArrayList<>();
users.add(user1);
users.add(user2);
users.add(user3);
users.add(user4);
users.add(user5);
test06(users);
}
/**
* flatMap
*/
public static void test12() {
List<List<Integer>> list = new ArrayList<>();
List<Integer> list1 = new ArrayList<>();
list1.add(1);
list1.add(2);
list1.add(3);
List<Integer> list2 = new ArrayList<>();
list2.add(10);
list2.add(20);
list2.add(30);
List<Integer> list3 = new ArrayList<>();
list3.add(100);
list3.add(200);
list3.add(300);
list.add(list1);
list.add(list2);
list.add(list3);
// flatMap用于将数据扁平化,用来处理有嵌套关系的数据。
// 如User{ List<Book> books>},用户数据中包含了图书信息,
// 想获取所有用户的图像信息(即获取到List<Book>),就可以使用flatMap。
// users.stream().flatMap(v -> v.getBooks().stream()).collect(Collectors.toList()));
// [1, 2, 3, 10, 20, 30, 100, 200, 300]
System.out.println(list.stream().flatMap(v -> v.stream()).collect(Collectors.toList()));
System.out.println(list.stream().flatMap(Collection::stream).collect(Collectors.toList()));
}
/**
* dropWhile takeWhile
*/
public static void test11() {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
// 删除第一个不满足条件的元素之前的所有元素,只要后面的其他元素。
// [2, 3, 4, 5]
System.out.println(list.stream().dropWhile(v -> v == 1).toList());
// 只保留流中第一个不满足条件的元素之前的所有元素。
// [1]
System.out.println(list.stream().takeWhile(v -> v == 1).toList());
}
/**
* allMatch、anyMatch、noneMatch、reduce。
*/
public static void test09() {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
// 都匹配
System.out.println(list.stream().allMatch(v -> v == 4)); // false
// 任何一个匹配
System.out.println(list.stream().anyMatch(v -> v == 4)); // true
// 所有的都没有匹配上。
System.out.println(list.stream().noneMatch(v -> v > 10)); // true
// 将流中元素相加
System.out.println(list.stream().reduce(Integer::sum).get()); // 10
// 获取元素第一个值
System.out.println(list.stream().reduce((first, second) -> first).get()); // 1
// 获取元素第二个值
System.out.println(list.stream().reduce((first, second) -> second).get()); // 4
}
/**
* map、peek。
*/
public static void test08() {
List<User> list = new ArrayList<>();
list.add(new User(1, "1"));
list.add(new User(2, "2"));
list.add(new User(3, "3"));
list.add(new User(4, "4"));
// 从小到大排序
list.stream().sorted().forEach(System.out::println);
// 从大到小排序,倒序。
list.stream().sorted((o1, o2) -> -o1.id - o2.id).forEach(System.out::println);
// map和peek的区别,map操作后可以改变流的返回值值;
// peek不能改变返回值,只是对流中元素进行操作。
list.stream().map(User::getId).forEach(System.out::println);
list.stream().peek(v -> v.setId(v.getId() - 1)).forEach(System.out::println);
String names02 = list.stream().map(User::getName)
.collect(Collectors.joining(",", "[", "]"));
// [tom1,tom2,tom3,tom4,tom4]
System.out.println(names02);
}
public static void test07() {
// 通过数组创建流。
int[] a = {1, 2, 3, 4, 5};
Arrays.stream(a).forEach(System.out::println);
// Stream创建流
Stream.of(1, 2, 3).forEach(System.out::println);
// 创建一个无限循环流。第二个参数是函数接口,函数的入参是第一个参数,
// 函数的返回值是对第一个参数的操作结果。
Stream.iterate(1, v -> v).forEach(System.out::println);
// 创建一个无限循环的流。
Stream.generate(Math::random).forEach(System.out::println);
}
/**
* List中对象id值加10
* @param list
*/
public static void test06(List<User> list) {
List<User> collect = list.stream().peek((v1) -> v1.setId(v1.getId() + 10))
.collect(Collectors.toList());
System.out.println(collect);
}
/**
* 分组。collect 收集器
* @param list
*/
public static void test05(List<User> list) {
// 通过List中对象的某一个属性进行分组
Map<String, List<User>> map = list.stream().collect(Collectors.groupingBy(User::getAddr));
System.out.println(map);
}
public static void test04(List<User> list) {
// 对Id列进行求和
Integer integer = list.stream().mapToInt(User::getId).sum();
System.out.println(integer);
}
public static void test03(List<User> list) {
// List转Map,将List中对象的某一个属性作为Map的key,这个属性对应的对象作为Map的value。
// v -> v,每次处理的值,这里可以对值进行操作,或者返回转换为其他对象。
// 当key重复了就会走到(v1, v2) -> v2中,由这个函数确定重复时需要保存哪个值。
// (v1, v2) -> v1,当出现多个key时,保留之前的值。
// (v1, v2) -> v2,当出现多个key时,进行覆盖,保存之后的值。
Map<String, User> stringUserMap01 = list.stream()
.collect(Collectors.toMap(User::getName, v -> v, (v1, v2) -> v2));
System.out.println(stringUserMap01);
// List转Map简写,保留最后一个key对应的value。
// 如果key重复会报错,Duplicate key。
Map<String, User> stringUserMap02 = list.stream().collect(Collectors.toMap(User::getName, v -> v));
System.out.println(stringUserMap02);
// List转Map简写,保留最后一个key对应的value。
// 如果key重复会报错,Duplicate key。
Map<String, User> stringUserMap03 = list.stream().collect(Collectors.toMap(User::getName, Function.identity()));
System.out.println(stringUserMap03);
}
/**
* List转List
* @param list
*/
public static void test02(List<User> list) {
// 选择List中所有对象的某一个属性值作为一个新List
List<String> collect = list.stream().map(User::getName).collect(Collectors.toList());
System.out.println(collect);
}
public static void test01(List<User> list) {
User user5 = new User(5, "tom5", 15, "t5");
list.add(user5);
// filter 过滤为true的值
list.stream()
// 过滤为true的值
.filter(v -> v.id > 2)
// 通过id排序倒序
.sorted(User::compareTo)
// 只输出前两个
.limit(2)
.forEach(System.out::println);
}
@Data
static class User implements Comparable<User> {
private Integer id;
private String name;
private Integer age;
private String addr;
public User(Integer id, String name, Integer age, String addr) {
this.id = id;
this.name = name;
this.age = age;
this.addr = addr;
}
@Override
public int compareTo(User o) {
return o.id - this.id;
}
}
}
3.Optional判空
public class OptionDemo {
public static void main(String[] args) {
demo01();
}
public static void demo01() {
User user1 = null;
// User1为空抛出异常
Optional.ofNullable(user1).orElseThrow(() -> new RuntimeException("user is null"));
// User1为空就返回一个新的User
User user3 = Optional.ofNullable(user1).orElse(new User());
// User1为空就返回一个新的User
User user4 = Optional.ofNullable(user1).orElseGet(User::new);
User user2 = new User();
// User2不为空将User2的id设置为10
Optional.ofNullable(user2).ifPresent(user -> user.id = 10);
System.out.println(user2.id);
// User2不为空,输出user2 is not null
if (Optional.ofNullable(user2).isPresent()) {
System.out.println("user2 is not null");
}
}
static class User {
Integer id;
public User() {}
public User(Integer id) {
this.id = id;
}
}
}
4.Double精度损失
/**
* double直接转BigDecimal会出现精度损失的问题,
* 可以使用Double.toString(d3)或者如果是Double类型可以使用Double.toString();
*/
public static void doubleDemo() {
double d1 = 12.49;
BigDecimal decimal = new BigDecimal(d1);
// 会出现精度损失。12.4900000000000002131628207280300557613372802734375
System.out.println(decimal);
Double d2 = 12.49;
// 12.49
decimal = new BigDecimal(d2.toString());
System.out.println(decimal);
double d3 = 12.49;
decimal = new BigDecimal(Double.toString(d3));
// 12.49
System.out.println(decimal);
}
5.BigDecimal
public static void test13() {
BigDecimal b1 = new BigDecimal("1.0");
BigDecimal b2 = new BigDecimal("1");
System.out.println(b1.equals(b2)); // false
System.out.println(b1.compareTo(b2)); // 0,相等。
BigDecimal b3 = new BigDecimal("1E11");
// 有必要时使用科学计数法
System.out.println(b3.toString()); // 1E+11
// 不使用任何指数(永不使用科学计数法)
System.out.println(b3.toPlainString()); // 100000000000
// 有必要时使用工程计数法。工程记数法是一种工程计算中经常使用的记录数字的方法,与科学计数法类似,但要求10的幂必须是3的倍数
System.out.println(b3.toEngineeringString()); // 100E+9
// stripTrailingZeros,去掉尾部不需要的零
BigDecimal b4 = new BigDecimal("1.000");
System.out.println(b4.stripTrailingZeros()); // 1
BigDecimal b5 = new BigDecimal("2.005");
// 四舍五入
System.out.println(b5.setScale(2, RoundingMode.HALF_UP)); // 2.01
// 银行家舍入法,主要在美国使用,四舍六入,五分两种情况,如果前一位为奇数,则入位,否则舍去。
System.out.println(b5.setScale(2, RoundingMode.HALF_EVEN)); // 2.00
}