JDK1.8新特性
1.Lambda表达式
Lambda是一个匿名函数,Lambda允许把函数作为一个方法的参数(函数作为参数传递到方法中),可以将Lambda表达式理解为是一段可以传递的代码。作为一种新语法,使得java语言表达能力得到提示,语言更加简洁,但也使得可读性变差。
1.1 lambda 表达式语法
lambda表达式语法:
主要通过->
箭头操作符分割为两部分,左边为lambda函数参数,右边一部分lambda函数体
//1
object -> expression
//2
(object1,object2) -> {}
1.2 Lambda表达式示例
public class LambdaTest {
public static void main(String[] args) {
//1.匿名内部类转换为lambda
Runnable t1 = new Runnable() {
@Override
public void run() {
System.out.println("runnable-匿名内部类");
}
};
t1.run();
//Anonymous new Runnable() replaced with lambda
Runnable t2 = () -> System.out.println("runnable-lambda");
t2.run();
//————————————————————————————
//2.带有一个参数的lambda语法
//一个参数,括号也可以省略
//数据类型可以省略
Consumer<String> consumer = (s) -> System.out.println(s);
consumer = s -> System.out.println(s);
consumer.accept("带有一个参数的lambda语法");
//————————————————————————————
//3.两个参数语法
Comparator<Integer> comparator = (o1, o2) ->{
System.out.println("o1:" + o1);
System.out.println("o2:" + o2);
return (o1<o2)? o2 :(o1);
};
//当只有一行代码时,可以省略写法
Comparator<Integer> comparator2 = (o1, o2) ->(o1<o2)? o2 :(o1);
comparator.compare(123, 12);
comparator2.compare(123, 12);
}
}
2.函数式接口
2.1 什么是函数式接口
只包含一个抽象方法的接口,在接口上添加 @FunctionalInterface 注解声明的为函数式接口,函数式接口可以隐式的转换为lambda表达式
/**
* Success callback for a {@link ListenableFuture}.
*
* @author Sebastien Deleuze
* @since 4.1
* @param <T> the result type
*/
@FunctionalInterface
public interface SuccessCallback<T> {
/**
* Called when the {@link ListenableFuture} completes with success.
* <p>Note that Exceptions raised by this method are ignored.
* @param result the result
*/
void onSuccess(@Nullable T result);
}
2.2 jdk1.8内置四大函数式接口
接口 | 描述 |
---|---|
Function<T,R> | 函数型接口 |
Consumer | 消费型接口 |
Supplier | 供给型接口 |
Predicate | 断言型接口 |
-
Function<T,R>:接收一个参数并产生一个结果
/** * Represents a function that accepts one argument and produces a result. * * <p>This is a <a href="package-summary.html">functional interface</a> * whose functional method is {@link #apply(Object)}. * * @param <T> the type of the input to the function * @param <R> the type of the result of the function * * @since 1.8 */ @FunctionalInterface public interface Function<T, R> { /** * Applies this function to the given argument. * * @param t the function argument * @return the function result */ R apply(T t); }
示例:
@org.junit.Test public void testFunction() { //转为大写 String str = testStr("fdasfd", a -> a.toUpperCase()); System.out.println(str); } public String testStr(String str, Function<String, String> function){ return function.apply(str); }
-
Consumer:接收一个参数,无任何返回值
/** * Represents an operation that accepts a single input argument and returns no * result. Unlike most other functional interfaces, {@code Consumer} is expected * to operate via side-effects. * * <p>This is a <a href="package-summary.html">functional interface</a> * whose functional method is {@link #accept(Object)}. * * @param <T> the type of the input to the operation * * @since 1.8 */ @FunctionalInterface public interface Consumer<T> { /** * Performs this operation on the given argument. * * @param t the input argument */ void accept(T t);
示例:
查看 **
Iterable
接口中的forEach()
方法,还是通过Consumer
**来调用for循环遍历/** * Implementing this interface allows an object to be the target of * the "for-each loop" statement. See * <strong> * <a href="{@docRoot}/../technotes/guides/language/foreach.html">For-each Loop</a> * </strong> * * @param <T> the type of elements returned by the iterator * * @since 1.5 * @jls 14.14.2 The enhanced for statement */ public interface Iterable<T> { /** * Returns an iterator over elements of type {@code T}. * * @return an Iterator. */ Iterator<T> iterator(); /** * Performs the given action for each element of the {@code Iterable} * until all elements have been processed or the action throws an * exception. Unless otherwise specified by the implementing class, * actions are performed in the order of iteration (if an iteration order * is specified). Exceptions thrown by the action are relayed to the * caller. * * @implSpec * <p>The default implementation behaves as if: * <pre>{@code * for (T t : this) * action.accept(t); * }</pre> * * @param action The action to be performed for each element * @throws NullPointerException if the specified action is null * @since 1.8 */ default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } }
-
Supplier: 供给型接口:没有输入参数,返回一个结果
/** * Represents a supplier of results. * * <p>There is no requirement that a new or distinct result be returned each * time the supplier is invoked. * * <p>This is a <a href="package-summary.html">functional interface</a> * whose functional method is {@link #get()}. * * @param <T> the type of results supplied by this supplier * * @since 1.8 */ @FunctionalInterface public interface Supplier<T> { /** * Gets a result. * * @return a result */ T get(); }
示例:
@org.junit.Test public void testRunSupplier() { testSupplier(()->"fdsafdsfds"); } private void testSupplier(Supplier<String> supplier){ System.out.println(supplier.get().toUpperCase()); }
-
Predicate:断言型接口,接受一个输入参数,返回一个布尔结果
/** * Represents a predicate (boolean-valued function) of one argument. * * <p>This is a <a href="package-summary.html">functional interface</a> * whose functional method is {@link #test(Object)}. * * @param <T> the type of the input to the predicate * * @since 1.8 */ @FunctionalInterface public interface Predicate<T> { /** * Evaluates this predicate on the given argument. * * @param t the input argument * @return {@code true} if the input argument matches the predicate, * otherwise {@code false} */ boolean test(T t);
示例:
@org.junit.Test public void testRunPredicate() { List<Integer> list = Arrays.asList(2,6,5); //大于2的数 List<Integer> integers = filterInt(list, num -> num > 2); System.out.println(integers); } public List<Integer> filterInt(List<Integer> nums ,Predicate<Integer> predicate){ List<Integer> intList = new ArrayList<Integer>(); for (Integer num : nums) { if(predicate.test(num)) intList.add(num); } return intList; }
3.默认方法
Java 8 增加了 **default
**方法,用于实现接口的默认实现方法,且不需要类去实现接口中的方法。这样对于已经存在的接口修改接口中的方法不用去修改所有的实现,解决之前的缺陷。
3.1 语法
package java.lang;
import java.util.Iterator;
import java.util.Objects;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Consumer;
public interface Iterable<T> {
Iterator<T> iterator();
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
3.2 多个默认方法
默认接口1:
public interface DeFaultInterfaceA {
default void print(){
System.out.println("默认方法A");
}
}
默认接口2:
public interface DeFaultInterfaceB {
default void print(){
System.out.println("默认方法B");
}
}
实现方式1:
public class DefaultTestImpl implements DeFaultInterfaceA,DeFaultInterfaceB{
@Override
public void print() {
System.out.print("我是自己的实现方法");
}
}
实现方式2:
public class DefaultTestImpl implements DeFaultInterfaceA,DeFaultInterfaceB{
@Override
public void print() {
//调用指定父类接口的方法
DeFaultInterfaceA.super.print();
}
}
3.3 静态默认方法
public interface DefaultStaticMethod {
static void test(){
System.out.println("接口的默认静态方法!");
}
}
4.方法引用,构造引用,数组引用
4.1 方法引用
如果lambda方法体中的功能以及有方法提供了实现,那么可以使用方法引用,可以理解为Lambda 表达式的另一种表现形式。
方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致。
4.1.1语法:
- 对象的引用 :: 实例方法名
- 类名 :: 静态方法名
- 类名 :: 实例方法名
4.1.2示例:
@org.junit.Test
public void testMethodRef(){
Consumer<String> consumer = (s -> System.out.println(s.toUpperCase()));
consumer.accept("abc,lambda表达式写法");
//对象的引用 :: 实例方法名
consumer = this::toUpperCase;
consumer.accept("aaa,方法引用写法");
}
private void toUpperCase(String str){
System.out.println(str.toUpperCase());
}
4.2 构造引用
4.2.1 语法
- 类名 :: new
4.2.2 说明
可以把构造器中的引用赋值给定义的方法
4.2.3 注意事项
构造器的参数列表,需要与函数式接口中参数列表保持一致。
4.2.5 示例
@org.junit.Test
public void testConstructorRef() {
//lambda写法
Function<String, BigDecimal> function = (a) -> new BigDecimal(a);
BigDecimal temp = function.apply("234");
System.out.println(temp);
//构造引用写法
Function<String, BigDecimal> function2 = BigDecimal::new;
BigDecimal temp2 = function2.apply("1321321");
System.out.println(temp2);
}
4.3 数组引用
4.3.1 语法
- 类型[] :: new
4.3.2 示例
@org.junit.Test
public void testArrayRef() {
//lambda写法
Function<Integer, BigDecimal[]> function = (a) -> new BigDecimal[a];
BigDecimal[] tempArray = function.apply(4);
System.out.println(tempArray.length);
//数组引用写法
Function<Integer, BigDecimal[]> function2 = BigDecimal[]::new;
BigDecimal[] tempArray2 = function2.apply(3);
System.out.println(tempArray2.length);
}
4.3.3 注意事项
输入参数类型为数组长度
5.java Stream
5.1 什么是stream ?
Stream
(流)是一个来自数据源的元素队列并支持聚合操作,帮助我们对更好地对数据进行集合操作。Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对Java集合运算和表达的高阶抽象。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选,排序,聚合等。
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
5.2 Stream特点
- 元素是特定类型的对象,形成一个队列。Java的Stream不会存储元素 ,而是根据元素计算出需要的数据。
- Stream 不会改变原对象,而是生成一个新的对象
- 聚合操作:max,min 等
5.3 生成流
@org.junit.Test
public void testCreateStream(){
//通过Collection 系列集合提供的 stream() 或 parallelStream()
List<String> list = new ArrayList<>();
// list.parallelStream()
Stream<String> stream = list.stream();
//2.通过Arrays中的静态方法stream()获取数组流
BigDecimal[] bigDecimals = new BigDecimal[10];
Stream<BigDecimal> stream1 = Arrays.stream(bigDecimals);
//3. 通过Stream类中的静态方法of()
Stream<String> aaa = Stream.of("aaa", "bbb", "ccc");
//4. 创建无限流
//迭代
Stream<Integer> iterate = Stream.iterate(1, (x) -> x + 3);
iterate.limit(10).forEach((x)-> System.out.println(x));
//生成
Stream.generate(()->(int)(Math.random()*100)).limit(10).forEach(System.out::println);
}
5.4 Stream中间操作
一个流可以后面跟随着0个或者多个中间操作,其目的是打开流,做出某种程度的数据过滤、去重、排序、映射、跳过等。然后返回一个新的流,交给下一个使用,仅仅是调用这个方法,没有真正开始遍历。
@org.junit.Test
public void testStreamHandle(){
//limit 截取指定数据量
List<Integer> list = Stream.generate(() -> (int) (Math.random() * 100)).limit(30).collect(Collectors.toList());
//filter 过滤出大于20的值
list.stream().filter(a -> a > 20).forEach(System.out::print);
System.out.println("------------------------------------------");
list = Arrays.asList(1,2,21,2,2,2,3,3,1,2,43);
//sorted排序 -- 正序
System.out.println("sorted:");
list.stream().sorted().forEach(System.out::print);
System.out.println("------------------------------------------");
//sorted排序 -- 倒序
list.stream().sorted(Comparator.comparingInt(t-> (int) t).reversed()).forEach(item->{
System.out.print(item+",");
});;
System.out.println("------------------------------------------");
System.out.println("distinct:");
//distinct 去重
list.stream().distinct().forEach(item->{
System.out.print(item+",");
});;
// skip跳过指定元素 返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流,与limit(n)互补
System.out.println("------------------------------------------");
System.out.println("skip:");
list.stream().skip(2).forEach(item->{
System.out.print(item+",");
});;
//映射
//map:接收Lambda,将元素转换成其他形式或提取信息,接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
//flatMap: 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
System.out.println("------------------------------------------");
System.out.println("map:");
list.stream().map(a->a + 2).forEach(item->{
System.out.print(item+",");
});
System.out.println("------------------------------------------");
System.out.println("flatMap:");
list.stream().flatMap(this::flatMapTest).forEach(item->{
System.out.print(item+",");
});
}
/**
* 为每个int值添加一个比它大1的值
* @param a
* @return
*/
private Stream<Integer> flatMapTest(Integer a){
return Stream.of(a,a+1);
}
5.5 终止操作
一个终止操作,执行中间操作连,产生结果。
forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator
6.Option 类
可以包含或者不包含非空值对象的容器,如果值存在 isPresent()
将返回 true
,并且 get()
将返回值;作用就是用来代表值存不存在,原来使用null来表示,现在使用Option可以更好的表示,并且可以避免空指针异常
示例:
@org.junit.Test
public void testOption(){
List<Integer> list = Arrays.asList(1, 2, 3, 3);
//获取第一个等于3的值
Optional<Integer> optionalInteger = list.stream().filter(o -> o.equals(3)).findFirst();
if(optionalInteger.isPresent()){
Integer result = optionalInteger.get();
System.out.println(result);
}
}
7.新增日期类
java.util.Date:月份从0开始,对象不是最终的可以修改
java.util.Calendar:月份依然从0开始
格式化时间线程不安全,且两个都不为最终类,都可改变
类 | 解释 |
---|---|
LocalDate | 本地日期(年月日) |
LocalTime | 本地时间(时分秒) |
LocalDateTime | 本地日期+时间 |
Instant | 时间戳,适合机器时间计算 |
Duration | 时间差 |
Period | 年、月、日差 |
ZoneOffset | 时区偏移量 |
ZonedDateTime | 带时区的日期时间 |
Clock | 时钟,获取其他地区时钟 |
DateTimeFormatter | 时间格式化 |
Temporal | 日期-时间获取值的字段 |
TemporalAdjuster | Temporal对象转换,实现自定义 |
ChronoLocalDate | 日历系统接口 |
示例:
@org.junit.Test
public void testNewDate(){
//获取当前日期
LocalDate nowLocalDate = LocalDate.now();
System.out.println(nowLocalDate);
//获取当前时间
LocalTime nowLocalTime = LocalTime.now();
System.out.println(nowLocalTime);
//日期时间
LocalDateTime localDateTime = LocalDateTime.of(2022,12,17,8,11,12);
System.out.println(localDateTime);
System.out.println(localDateTime.getDayOfMonth());
System.out.println(localDateTime.getHour());
LocalDateTime nowLocalDateTime = LocalDateTime.now();
Duration between = Duration.between(localDateTime, nowLocalDateTime);
System.out.println("相差小时:"+between.toHours());
}
输出结果:
2022-12-17
11:23:26.136
2022-12-17T08:11:12
17
8
相差小时:3