精华内容
下载资源
问答
  • 2022-05-10 22:49:13

    问题:ArrayList和LinkedList的区别

    难度:★★★★

    工资提升度:★★☆

    博主精选答案:

    一、接口的默认方法


    Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用default关键字即可,这个特征又叫做扩展方法,示例如下:
    代码如下:
    interface Formula { double calculate(int a);
    default double sqrt(int a) { return Math.sqrt(a); } }
    Formula接口在拥有calculate方法之外同时还定义了sqrt方法,实现了Formula接口的子类只需要实现一个calculate方法,默认方法sqrt将在子类上可以直接使用。
    代码如下:
    Formula formula = new Formula() { @Override public double calculate(int a) { return sqrt(a * 100);}};formula.calculate(100);1/ 100.0 formula.sqrt(16);//4.0
    文中的formula被实现为一个匿名类的实例,该代码非常容易理解,6行代码实现了计算sqrt(a *100)。在下一节中,我们将会看到实现单方法接口的更简单的做法。
    译者注:在Java中只有单继承,如果要让一个类赋予新的特性,通常是使用接口来实现,在C++中支持多继承,允许一个子类同时具有多个父类的接口与功能,在其他语言中,让一个类同时具有其他的可复用代码的方法叫做mixin。新的Java 8的这个特新在编译器实现的角度上来说更加接近Scala的trait。在C#中也有名为扩展方法的概念,允许给已存在的类型扩展方法,和ava 8的这个在语义上有差别

    二、Lambda表达式

    首先看看在老版本的Java中是如何排列字符串的:代码如下:
    List<string> names = Arrays.asList(""peterF"", "anna", "mike", ""xenia");
    Collections.sort(names, new Comparator<string>(){ @override public int compare(String a, String b){return b.compareTo(a); } 3);
    只需要给静态方法Collections.sort传入一个List对象以及一个比较器来按指定顺序排列。通常做法都是创建一个匿名的比较器对象然后将其传递给sort方法。
    在Java 8中你就没必要使用这种传统的匿名对象的方式了,Java 8提供了更简洁的语法,lambda表达式:代码如下:
    Collections.sort(names,(String a, String b)-> { return b.compareTo(a); });看到了吧,代码变得更段且更具有可读性,但是实际上还可以写得更短:代码如下:
    Collections.sort(names, (String a, String b)-> b.compareTo(a));
    对于函数体只有一行代码的,你可以去掉大括号(以及return关键字,但是你还可以写得更短点:代码如下:
    Collections.sort(names, (a, b)-> b.compareTo(a));
    Java编译器可以自动推导出参数类型,所以你可以不用再写一次类型。

    三、函数式接口


    Lambda表达式是如何在java的类型系统中表示的呢?每一个lambda表达式都对应一个类型,通常是接口类型。而"函数式接口”是指仅仅只包含一个抽象方法的接口,每一个该类型的lambda表达式都会被匹配到这个抽象方法。因为默认方法不算抽象方法,所以你也可以给你的函数式接口添加默认方法。
    我们可以将lambda表达式当作任意只包含一个抽象方法的接口类型,确保你的接口一定达到这个要求,你只需要给你的接口添加@Functionallnterface注解,编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的。
    示例如下:代码如下:
    @Functionallnterface interface Converter<F,T> { T convert(F from); } Converter<String, Integer> converter=(from) -> Integer.valueOf(from); Integer converted = converter.convert("123"");
    System.out.printIn(converted); ll 123
    需要注意如果@Functionallnterface如果没有指定,上面的代码也是对的。
    译者注将lambda表达式映射到一个单方法的接口上,这种做法在Java 8之前就有别的语言实现,比如RhinoJavaScript解释器,如果一个函数参数接收一个单方法的接口而你传递的是一个function,Rhino解释器会自动做一个单接口的实例到function的适配器,典型的应用场景有org.w3c.dom.events.EventTarget的
    addEventListener第二个参数EventListener。

    四、方法与构造函数引用


    前一节中的代码还可以通过静态方法引用来表示:代码如下:
    Converter<String, Integer> converter = Integer:valueOf; Integer converted = converter.convert("123");System.out.printIn(converted); 1/ 123
    Java 8允许你使用:关键字来传递方法或者构造函数引用,上面的代码展示了如何引用一个静态方法,我们也可以引用一个对象的方法:
    代码如下:
    converter = something:startsWith; String converted = converter.convert("Java");System.out.printIn(converted); 11 "”
    接下来看看构造函数是如何使用::关键字来引用的,首先我们定义一个包含多个构造函数的简单类:代码如下:
    class Person { String firstName; String lastName;Person()0
    person(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } }接下来我们指定一个用来创建Person对象的对象工厂接口:
    代码如下:
    interface PersonFactory<P extends Person> { P create(String firstName, String lastName); }
    这里我们使用构造函数引用来将他们关联起来,而不是实现一个完整的工厂:
    代码如下:
    PersonFactory<Person> personFactory = Person:new; Person person = personFactory.create("Peter""Parker");
    我们只需要使用Person:new来获取Person类构造函数的引用,Java编译器会自动根据PersonFactory.create方法的签名来选择合适的构造函数。
     

    五、Lambda 作用域


    在lambda表达式中访问外层作用域和老版本的匿名对象中的方式很相似。你可以直接访问标记了final的外层局部变量,或者实例的字段以及静态变量。


    六、访问局部变量


    我们可以直接在lambda表达式中访问外层的局部变量:代码如下:
    final int num = 1; Converter<Integer, String stringConverter = (from) -> String.valueOf(from + num);stringConverter.convert(2); 1/ 3
    但是和匿名对象不同的是,这里的变量num可以不用声明为final,该代码同样正确:代码如下:
    int num = 1; Converter<Integer, String stringConverter = (from) -> String.valueOf(from + num);stringConverter.convert(2); 1l 3
    不过这里的num必须不可被后面的代码修改(即隐性的具有final的语义),例如下面的就无法编译:代码如下:
    int num = 1;Converter<Integer, String> stringConverter =(from)->String.valueOffrom + num); num = 3;在lambda表达式中试图修改num同样是不允许的。

    七、访问对象字段与静态变量


    和本地变量不同的是,lambda内部对于实例的字段以及静态变量是即可读又可写。该行为和匿名对象是一致的:代码如下:
    class Lambda4 { static int outerStaticNum; int outerNum;
    void testScopes() { Converter<Integer, String> stringConverter1 =(from) -> { outerNum = 23; returnString.valueOf(from); };
    Converter<Integer, String> stringConverter2 = (from)-> { outerStaticNum = 72; returnstring.valueOf(from); 1;}}


    八、访问接口的默认方法


    还记得第一节中的formula例子么,接口Formula定义了一个默认方法sqrt可以直接被formula的实例包括匿名对象访问到,但是在lambda表达式中这个是不行的。Lambda表达式中是无法访问到默认方法的,以下代码将无法编译:
    代码如下:
    Formula formula = (a) -> sqrt( a * 100); Built-in Functional Interfaces
    JDK 1.8API包含了很多内建的函数式接口,在老Java中常用到的比如Comparator或者Runnable接口,这些接口都增加了@Functionallnterface注解以便能用在lambda上。Java 8 API同样还提供了很多全新的函数式接口来让工作更加方便,有一些接口是来自Google Guava库里的,即便你对这些很熟悉了,还是有必要看看这些是如何扩展到lambda上使用的。

    九、新的接口和类(不是很重要)

    predicate接口
    Predicate接口只有一个参数,返回boolean类型。该接口包含多种默认方法来将Predicate组合成其他复杂的逻辑(比如:与,或,非):
    代码如下:
    Predicate<string> predicate =(s)-> s.length() > 0;
    predicate.test(""foo""); ll true predicate.negate().test(""foo"); ll false
    Predicate<Boolean> nonNull = Objects:nonNull; Predicate<Boolean> isNull = Objects:isNull;Predicate<string> isEmpty = String:isEmpty; Predicate<string> isNotEmpty = isEmpty.negate();

    Function接口
    Function接口有一个参数并且返回一个结果,并附带了一些可以和其他函数组合的默认方法(compose,andThen) :
    代码如下:
    Function<String, Integer> toInteger = Integer::valueOf; Function<String, String backToString =tolnteger.andThen(String::valueOf);
    backToString.apply("123");11 "123"

    Supplier接口
    Supplier接口返回一个任意范型的值,和Function接口不同的是该接口没有任何参数

    代码如下:
    Supplier<Person> personSupplier = Person:new; personSupplier.get(); /l/ new Person

    Consumer接口Consumer接口表示执行在单个参数上的操作。
    代码如下:
    Consumer<Person> greeter=(p)-> System.out.printIn("Hello, " + p.firstName); greeter.accept(newPerson("Luke", "Skywalker"));


    Comparator接口Comparator是老Java中的经典接口,Java 8在此之上添加了多种默认方法:

    代码如下:
    Comparator<Person> comparator =(p1, p2)-> p1.firstName.compareTo(p2.firstName);Person p1 = new Person("John" , "Doe"); Person p2 = new Person("Alice" ,""Wonderland";comparator.compare(p1, p2);/l > 0 comparator.reversed().compare(p1, p2);ll<O
     

    optional接口
    Optional不是函数是接口,这是个用来防止NullPointerException异常的辅助类型,这是下一届中将要用到的重要概念,现在先简单的看看这个接口能干什么:
    Optional被定义为一个简单的容器,其值可能是null或者不是null。在Java 8之前一般某个函数应该返回非空对象但是偶尔却可能返回了null,而在Java8中,不推荐你返回null而是返回Optional。
    代码如下:
    Optional<string> optional = Optional.of("bam");
    optional.isPresent(); /l true optional.get(); ll "bam" optional.orElse("fallback"); // ""bam"
    optional.ifPresent((s)-> System.out.println(s.charAt(O))); 1/""b"

    Stream接口
    java.util.Stream表示能应用在一组元素上一次执行的操作序列。Stream操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回Stream本身,这样你就可以将多个操作依次串起来。
    Stream的创建需要指定一个数据源,比如java.util.Collection的子类,List或者Set,Map不支持。Stream的操作可以串行执行或者并行执行。
    首先看看Stream是怎么用,首先创建实例代码的用到的数据List:代码如下:
    List<string> stringCollection = new ArrayList<>(); stringCollection.add("ddd2");
    stringCollection.add("aaa2"); stringCollection.add(""bbb1"); stringCollection.add("aaa1");stringCollection.add("bbb3"); stringCollection.add("ccc"); stringCollection.add("bbb2");stringCollection.add("ddd1");
    Java 8扩展了集合类,可以通过Collection.stream()或者Collection.parallelStream()来创建一个Stream。:


    Filter过滤
    过滤通过一个predicate接口来过滤并只保留符合条件的元素,该操作属于中间操作,所以我们可以在过滤后的结果来应用其他Stream操作(比如forEach)。forEach需要一个函数来对过滤后的元素依次执行。forEach是一个最终操作,所以我们不能在forEach之后来执行其他Stream操作。
    代码如下:
    stringCollection .stream() .filter((s) -> s.startsWith("a"7)) .forEach(System.out:println);//"aaa2", "aaa1"


    Sort排序
    排序是一个中间操作,返回的是排序好后的Stream。如果你不指定一个自定义的Comparator则会使用默认排序。
    代码如下:
    stringCollection .stream() .sorted() .filter((s) -> s.startsWith("a")).forEach(System.outprintIn);// "aaa1", "aaa2"
    需要注意的是,排序只创建了一个排列好后的Stream,而不会影响原有的数据源,排序之后原数据stringCollection是不会被修改的:
    代码如下:
    System.out.printIn(stringCollection); //ddd2, aaa2, bbb1, aaa1, bbb3, ccc, bbb2, ddd1


    Map映射中间操作map会将元素根据指定的Function接口来依次将元素转成另外的对象,下面的示例展示了将字符串转换为大写字符串。你也可以通过map来讲对象转换成其他类型,map返回的Stream类型是根据你map传递进去的函数的返回值决定的。
    代码如下;
    stringCollection .stream() .map(String:toUpperCase) .sorted((a, b)-> b.compareTo(a)).forEach(System.out::println);
    1/"DDD2"",""DDD1","CCC","BBB3""""BBB2""""AAA2""""AAA1"

    Match匹配
    Stream提供了多种匹配操作,允许检测指定的Predicate是否匹配整个Stream。所有的匹配操作都是最终操作,并返回一个boolean类型的值。
    代码如下:
    boolean anyStartsWithA = stringCollection .stream() .anyMatch((s)-> s.startsWith(" a"));System.out.println(anyStartsWithA); ll true
    boolean allStartsWithA = stringCollection .stream() .allMatch((s)-> s.startsWith("a"));System.out.println(allStartsWithA); // false
    boolean noneStartsWithZ= stringCollection .stream() .noneMatch((s) -> s.startsWith("z"));System.out.println(noneStartsWithz); // true
    count计数计数是一个最终操作,返回Stream中元素的个数,返回值类型是long.代码如下:
    long startsWithB = stringCollection .stream() .filter((s) -> s.startsWith(""b")) .count();System.out.println(startsWithB); 1l 3
    Reduce规约
    这是一个最终操作,允许通过指定的函数来讲stream中的多个元素规约为一个元素,规越后的结果是通过Optional接口表示的:
    代码如下:
    Optional<string> reduced = stringCollection .stream().sorted() .reduce((s1, s2)->s1+ "#"+s2);reduced.ifPresent(System.out:printIn); /ll "aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2"

    并行**Streams**
    前面提到过Stream有串行和并行两种,串行Stream上的操作是在一个线程中依次完成,而并行Stream则是在多个线程上同时执行。
    下面的例子展示了是如何通过并行Stream来提升性能:首先我们创建一个没有重复元素的大表:
    代码如下:
    int max = 1000000; List<string> values = new ArrayList<>(max); for (int i = 0; i < max; i++) ( UUID uuid =UUID.randomUUID(); values.add(uuid.toString0));}
    然后我们计算一下排序这个Stream要耗时多久,串行排序:代码如下:
    long to = System.nanoTime();
    long count = values.stream().sorted().count(); System.out.printIn(count);long t1 = System.nanoTime();
    long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0); System.out.printIn(String.format("sequential sorttook: %d ms", millis));
    //串行耗时: 899 ms并行排序:
    代码如下:
    long to = System.nanoTime();
    long count = values.parallelStream().sorted().count(); System.out.printIn(count);long t1 = System.nanoTime();
    long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0); System.out.printIn(String.format("parallel sort took:%d ms", millis));
    //并行排序耗时:472ms上面两个代码几乎是一样的,但是并行版的快了50%之多,唯一需要做的改动就是将stream()改为parallelStream().
    Map
    前面提到过,Map类型不支持stream,不过Map提供了一些新的有用的方法来处理一些日常任务。代码如下:
    Map<lnteger, String> map = new HashMap<>();
    for (int i = o; i<10; i++) { map.putlfAbsent(i, "val" + i);}
    map.forEach((id, val) -> System.out.printIn(val);以上代码很容易理解, putfAbsent 不需要我们做额外的存在性检查,而forEach则接收一个Consumer接口来对map里的每一个键值对进行操作。
    下面的例子展示了map上的其他有用的函数:
    代码如下:

    Map<Integer, String> map = new HashMap<>();
    for (int i = 0; i< 10; i++) { map.putlfAbsent(i, "val" + i);}
    map.forEach((id, val)-> System.out.printIn(val);以上代码很容易理解,putifAbsent 不需要我们做额外的存在性检查,而forEach则接收一个Consumer接口来对map里的每一个键值对进行操作。
    下面的例子展示了map上的其他有用的函数:
    代码如下:
    map.computelfPresent(3, (num, val) -> val + num); map.get(3); // val33map.computelfPresent(9,(num, val) -> null); map.containsKey(9); // falsemap.computelfAbsent(23, num -> "val" + num); map.containsKey(23); ll truemap.computelfAbsent(3, num -> "bam"); map.get(3); // val33
    接下来展示如何在Map里删除一个键值全都匹配的项:
    代码如下:
    map.remove(3, "val3"); map.get(3); // val33map.remove(3, "val33"); map.get(3); ll null另外一个有用的方法:
    代码如下:
    map.getOrDefault(42, "not found""); // not found对Map的元素做合并也变得很容易了:
    代码如下:
    map.merge(9, "val9", (value, newValue) -> value.concat(newValue)); map.get(9);// val9
    map.merge(9, "concat", (value, newValue)-> value.concat(newValue)); map.get(9); // val9concatMerge做的事情是如果键名不存在则插入,否则则对原键对应的值做合并操作并重新插入到map中。九、Date API
    Java 8在包java.time下包含了一组全新的时间日期API。新的日期API和开源的Joda-Time库差不多,但又不完全一样,下面的例子展示了这组新API里最重要的一些部分:
    Clock时钟
    Clock类提供了访问当前日期和时间的方法,Clock是时区敏感的,可以用来取代System.currentTimeMilis()来获取当前的微秒数。某一个特定的时间点也可以使用Instant类来表示,Instant类也可以用来创建老的java.util.Date对象

    代码如下:
    Clock clock = Clock.systemDefaultZone(); long millis = clock.millis);
    Instant instant = clock.instant(; Date legacyDate = Date.from(instant);// legacy java.util.Date

    Timezones时区
    在新API中时区使用Zoneld来表示。时区可以很方便的使用静态方法of来获取到。时区定义了到UTS时间的时间差,在Instant时间点对象到本地日期对象之间转换的时候是极其重要的。
    代码如下:
    System.out.println(Zoneld.getAvailableZonelds(); //prints all available timezone idsZoneld zone1 =Zoneld.of("Europe/Berlin"); Zoneld zone2 = Zoneld.of(""Brazil/East");System.out.printIn(zone1.getRules()); System.out.printIn(zone2.getRules());
     ZoneRules[currentStandardOffset=+01:00]//ZoneRules[currentStandardOffset=-03:00]

    LocalTime本地时间
    LocalTime定义了一个没有时区信息的时间,例如晚上10点,或者17:30:15。下面的例子使用前面代码创建的时区创建了两个本地时间。之后比较时间并以小时和分钟为单位计算两个时间的时间差:
    代码如下:
    LocalTime now1 =LocalTime.now(zone1); LocalTime now2 = LocalTime.now(zone2);

    System.out.printIn(now1.isBefore(now2)); // false
    long hoursBetween = ChronoUnit.HOURS.between(now1, now2); long minutesBetween =ChronoUnit.MINUTES.between(now1, now2);
    System.out.printIn(hoursBetween); // -3 System.out.printIn(minutesBetween);// -239

    LocalTime提供了多种工厂方法来简化对象的创建,包括解析时间字符串。


    LocalTime本地时间
    LocalTime定义了一个没有时区信息的时间,例如晚上10点,或者17:30:15。下面的例子使用前面代码创建的时区创建了两个本地时间。之后比较时间并以小时和分钟为单位计算两个时间的时间差:
    代码如下:
    LocalTime now1 = LocalTime.now(zone1); LocalTime now2 = LocalTime.now(zone2);System.out.println(now1.isBefore(now2)); ll false
    long hoursBetween = ChronoUnit.HOURS.between(now1, now2); long minutesBetween =ChronoUnit.MINUTES.between(now1 , now2);
    System.out.printIn(hoursBetween); // -3 System.out.printIn(minutesBetween); // -239LocalTime提供了多种工厂方法来简化对象的创建,包括解析时间字符串。
    代码如下:
    LocalTime late = LocalTime.of(23,59,59); System.out.println(late); // 23:59:59
    DateTimeFormatter germanFormatter = DateTimeFormatter .ofLocalizedTime(FormatStyle.SHORT).withLocale(Locale.GERMAN);
    LocalTime leetTime = LocalTime.parse("13:37" , germanFormatter); System.out.printIn(leetTime);// 13:37

    LocalDateTime本地日期时间
    LocalDateTime同时表示了时间和日期,相当于前两节内容合并到一个对象上了。LocalDateTime和LocalTime还有LocalDate一样,都是不可变的。LocalDateTime提供了一些能访问具体字段的方法。
    代码如下:
    LocalDateTime sylvester = LocalDateTime.of(2014,Month.DECEMBER,31,23,59,59);
    DayOfWeek dayOfWeek = sylvester.getDayOfWeek); System.out.printin(dayOfWeek);// WEDNESDAYMonth month = sylvester.getMonth(); System.out.printIn(month);// DECEMBER
    long minuteOfDay = sylvester.getLong(ChronoField.MINUTE_OF_DAY); System.out.printIn(minuteOfDay); //1439
    只要附加上时区信息,就可以将其转换为一个时间点Instant对象,Instant时间点对象可以很容易的转换为老式的java.util.Date。
    代码如下:
    Instant instant = sylvester .atZone(Zoneld.systemDefault()) .tolnstant();
    Date legacyDate = Date.from(instant); System.out.printIn(legacyDate);/l Wed Dec 3123:59:59 CET 2014格式化LocalDateTime和格式化时间和日期一样的,除了使用预定义好的格式外,我们也可以自己定义格式:代码如下:
    DateTimeFormatter formatter = DateTimeFormatter .ofPattern("MMM dd, yy - HH:mm");
    LocalDateTime parsed =LocalDateTime.parse("Nov 03,2014-07:13", formatter); String string =formatter.format(parsed); System.out.printIn(string); // Nov 03,2014-07:13
    和java.text.NumberFormat不一样的是新版的DateTimeFormatter是不可变的,所以它是线程安全的。

    十、 Annotation注解


    在Java 8中支持多重注解了,先看个例子来理解一下是什么意思。首先定义一个包装类Hints注解用来放置一组具体的Hint注解:
    代码如下:
    interface Hints { Hintvalue(); }
    @Repeatable(Hints.class)@interface Hint { String value(); }
    Java 8允许我们把同一个类型的注解使用多次,只需要给该注解标注一下@Repeatable即可。例1:使用包装类当容器来存多个注解(老方法)
    代码如下:
    @Hints({@Hint(hint1"),@Hint("hint2"))) class Person 0例2:使用多重注解(新方法)
    代码如下:
    @Hint("hint1") @Hint("hint2") class Person0
    第二个例子里java编译器会隐性的帮你定义好@Hints注解,了解这一点有助于你用反射来获取这些信息:代码如下:

    Hint hint = Person.class.getAnnotation(Hint.class); System.out.printIn(hint);// null
    Hints hints1 = Person.class.getAnnotation(Hints.class);System.out.printIn(hints1.value().length);//2

    Hint[]hints2 = Person.class.getAnnotationsByType(Hint.class);

    System.out.printIn(hints2.length); // 2

    即便我们没有在Person类上定义@Hints注解,我们还是可以通过getAnnotation(Hints.class)来获取@Hints注解,更加方便的方法是使用getAnnotationsByType可以直接获取到所有的@Hint注解。另外Java 8的注解还增加到两种新的target上了:
    代码如下:
    @Target((ElementType.TYPE_PARAMETER, ElementType.TYPE_USE))@interface MyAnnotation (关于Java 8的新特性就写到这了,肯定还有更多的特性等待发掘。JDK 1.8里还有很多很有用的东西,比如Arrays.parallelSort, StampedLock和CompletableFuture等等。











     

    更多相关内容
  • JDK1.8新特性:JDK1.8究竟那些新特性JDK1.8概述 JDK1.8,又称之为Java 8(我习惯叫它为JDK1.8,后续统一叫做JDK1.8),是Java语言开发的一个主要版本。Oracle公司于2014年3月18日发布,它支持函数式编程,的...

    JDK1.8新特性:JDK1.8究竟有那些新特性呢

    JDK1.8概述

    JDK1.8,又称之为Java 8(我习惯叫它为JDK1.8,后续统一叫做JDK1.8),是Java语言开发的一个主要版本。Oracle公司于2014年3月18日发布,它支持函数式编程,新的JavaScript引擎,新的日期API,新的Stream API等。

    JDK1.8相比1.7之前版本,有以下几方面的优化:

    速度更快;

    代码更少(Lambda表达式);

    强大Stream API;

    便于并行;

    最大化减少空指针异常(OPtional类)。

    举例如下,JDK1.8的特性是不是与众不同。

    package com.xcbeyond.study.jdk8;
    
    import org.junit.Test;
    import java.util.Arrays;
    import java.util.List;
    
    /**
     * JDK1.8新特性
     * @Auther: xcbeyond
     * @Date: 2019/11/27 0027 23:53
     */
    public class Java8Test {
    
        @Test
        public void java8Example() {
            // 定义一个整型list,对其进行遍历
            Integer[] numArray={1,2,3,4,5,6,7,8};
            List<Integer> numList= Arrays.asList(numArray);
    
            /**
             * 方式1:常规foreach
             */
            for (int num : numList) {
                System.out.println(num);
            }
    
            /**
             * 方式2:JDK1.8 新特性写法(Lambda表达式)
             *  代码量是不是少了很多
             */
            numList.forEach((num) -> System.out.println(num));
        }
    }
    

    新特性

    JDK1.8新增了非常多的特性,本专题主要讨论以下几个:

    Lambda表达式:Lambda允许把函数作为一个方法的参数(函数作为参数传递到方法中)。
    方法引用:方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
    默认方法:默认方法就是一个在接口里面有了一个实现的方法。
    新工具:新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps。
    Stream API:新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
    Date Time API:加强对日期与时间的处理。
    Optional类:Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
    Nashorn,JavaScript引擎:JDK1.8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。

    Lambda 表达式的结构

    一个 Lambda 表达式可以有零个或多个参数
    参数的类型既可以明确声明,也可以根据上下文来推断。例如:(int a)与(a)效果相同
    所有参数需包含在圆括号内,参数之间用逗号相隔。例如:(a, b) 或 (int a, int b) 或 (String a, int b, float c)
    空圆括号代表参数集为空。例如:() -> 42
    当只有一个参数,且其类型可推导时,圆括号()可省略。例如:a -> return a*a
    Lambda 表达式的主体可包含零条或多条语句
    如果 Lambda 表达式的主体只有一条语句,花括号{}可省略。匿名函数的返回类型与该主体表达式一致
    如果 Lambda 表达式的主体包含一条以上语句,则表达式必须包含在花括号{}中(形成代码块)。匿名函数的返回类型与代码块的返回类型一致,若没有返回则为空

    Lambda 表达式重要特征

    可选类型声明 - 无需声明参数的类型。编译器可以从该参数的值推断。

    可选圆括号参数 - 无需在括号中声明参数。对于多个参数,括号是必需的。

    可选大括号 - 表达式主体没有必要使用大括号,如果主体中含有一个单独的语句。

    可选return关键字 - 编译器会自动返回值,如果主体有一个表达式返回的值。花括号是必需的,以表明表达式返回一个值。

    小试牛刀

    new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("我是传统的写法");
                }
            }).start();
    //------------------------------------------------------------
    new Thread(() -> System.out.println("我是Lambda的写法")).start();
    
    

    输出结果
    在这里插入图片描述

    Stream

    Stream是一组用来处理数组,集合的API。

    1.1 特性
    不是数据结构,没有内部存储。
    不支持索引访问。
    延迟计算
    支持并行
    很容易生成数据或集合
    支持过滤,查找,转换,汇总,聚合等操作。
    1.2 运行机制
    Stream分为源source,中间操作,终止操作。

    流的源可以是一个数组,集合,生成器方法,I/O通道等等。

    一个流可以有零个或多个中间操作,每一个中间操作都会返回一个新的流,供下一个操作使用,一个流只会有一个终止操作。

    Stream只有遇到终止操作,它的源才会开始执行遍历操作。

    1.1 Stream的创建

    1.通过数组,Stream.of()
    2.通过集合
    3.通过Stream.generate方法来创建
    4.通过Stram.iterate方法
    5.其他API

    import java.util.Arrays;
        import java.util.List;
        import java.util.stream.IntStream;
        import java.util.stream.Stream;
        
        public class CreateStream {
        
        	//通过数组,Stream.of()
            static void gen1(){
                String[] str = {"a","b","c"};
                Stream<String> str1 = Stream.of(str);
            }
        
        	//通过集合
            static void gen2(){
                List<String> strings = Arrays.asList("a", "b", "c");
                Stream<String> stream = strings.stream();
            }
        
        	//通过Stream.generate方法来创建
            static void gen3(){
            	//这是一个无限流,通过这种方法创建在操作的时候最好加上limit进行限制
                Stream<Integer> generate = Stream.generate(() -> 1);
                generate.limit(10).forEach(x -> System.out.println(x));
            }
            
        	//通过Stram.iterate方法
            static void gen4(){
                Stream<Integer> iterate = Stream.iterate(1, x -> x +1);
                iterate.forEach(x -> System.out.println(x));
            }
        
        	//其他API
            static void gen5(){
                String str = "abc";
                IntStream chars = str.chars();## 标题
                chars.forEach(x -> System.out.println(x));
            }
        }
    
    

    日期和时间

    • Instant 本质上是一个数字时间戳。可以从a中检索当前的Instant Clock。这对于某个时间点的日志记录和持久性非常有用。
    • LocalDateTime 存储日期和时间。这会存储类似’2010-07-23T15:47:25.890’的日期时间。
    • .ZonedDateTime 使用时区存储日期和时间。如果您想要考虑到日期和时间的准确计算ZoneId,例如“欧洲/巴黎”,这将非常有用。在可能的情况下,建议使用没有时区的更简单的类。时区的广泛使用往往会给应用程序增加相当大的复杂性
    • LocalTime 没有日期存储时间。存储像’11:30’这样的时间,可用于存储开盘或收盘时间。
    • Instant 本质上是一个数字时间戳。可以从a中检索当前的Instant Clock。这对于某个时间点的日志记录和持久性非常有用。

    其他类型

    • Month 用来存储一个月。这样可以隔离单个月份,例如“DECEMBER”。
    • DayOfWeek 用来存储一个星期的日子。这样可以隔离存储一个星期几,例如“星期二”
    • Year 用来存储一年。这样可以隔离一年,例如’2010’。
    • YearMonth 用来存储年加月份的时间。这会存储一年和一个月,例如“2010-12”,并可用于信用卡到期。
    • MonthDay 用来存储月份和日子。它存储月份和日期,例如“12-03”,可用于存储年度活动,如生日,而不存储年份。

    Spring Data API

    
    <!--java 8 time date 支持-->
    <dependency>
    	<groupId>org.hibernate</groupId>
    	<artifactId>hibernate-java8</artifactId>
    	<version>5.0.12.Final</version>
    </dependency>
    

    MyBatis

    <dependency>
    	<groupId>org.mybatis</groupId>
    	<artifactId>mybatis-typehandlers-jsr310</artifactId>
    	<version>1.0.1</version>
    </dependency>
    
    展开全文
  • jdk1.8新特性

    2022-03-07 21:31:57
    1.Lambda表达式 2.函数式接口 常见的四大函数式接口: (1) Consumer<... :消费型接口,参无... 断言型接口 返回值 返回值是boolean类型 3.方法引用 4.Stream API 5.并行流和串行流 ...

    1.Lambda表达式

    2.函数式接口

    常见的四大函数式接口:

    (1) Consumer<T> :消费型接口,有参无返回值

    (2).Suppiler<T> 攻击性接口,无参有返回值

    (3).Function<T,R> 函数式接口 有参有返回值

     (4).Predicate<T> 断言型接口  有参有返回值  返回值是boolean类型

     3.方法引用

     4.Stream API

     

     

     5.并行流和串行流

    6.ForkJoin框架 

    7.Optional容器

    使用Optional容器可以快速的定位NPE,并且在一定程度上 可以减少对参数非空检验的代码量

    8.新的日期 API LocalDate /LocalTime/LocalDateTime 

    新日期的几个优点:

     * 之前使用的java.util.Date月份从0开始,我们一般会+1使用,很不方便,java.time.LocalDate月份和星期都改成了enum
     * java.util.Date和SimpleDateFormat都不是线程安全的,而LocalDate和LocalTime和最基本的String一样,是不变类型,不但线程安全,而且不能修改。
     * java.util.Date是一个“万能接口”,它包含日期、时间,还有毫秒数,更加明确需求取舍
     * 新接口更好用的原因是考虑到了日期时间的操作,经常发生往前推或往后推几天的情况。用java.util.Date配合Calendar要写好多代码,而且一般的开发人员还不一定能写对。
    

    展开全文
  • JDK1.8特性(一):JDK1.8究竟有哪些新特性

    万次阅读 多人点赞 2019-12-22 13:43:34
    目前JDK1.8被各大公司、...今天抽时间整理下,JDK1.8新特性究竟有哪些?并以【JDK1.8新特性】专题逐一展开讨论、学习。 (JDK1.8新特性常常在面试中被问及的频率很高哦) JDK1.8概述 JDK1.8,又称之为Java 8(我习...

    在这里插入图片描述
    目前JDK1.8被各大公司、各大项目纷纷使用,作为Java开发中使用最多的版本,细心的你,或许早已发现它与之前版本存在着较大的差异。如果能熟练掌握使用这些差异、新特性,你会发现另一片天地。今天抽时间整理下,JDK1.8新特性究竟有哪些?并以【JDK1.8新特性】专题逐一展开讨论、学习。

    (JDK1.8新特性常常在面试中被问及的频率很高哦)

    JDK1.8概述

    JDK1.8,又称之为Java 8(我习惯叫它为JDK1.8,后续统一叫做JDK1.8),是Java语言开发的一个主要版本。Oracle公司于2014年3月18日发布,它支持函数式编程,新的JavaScript引擎,新的日期API,新的Stream API等。

    JDK1.8相比1.7之前版本,有以下几方面的优化:

    • 速度更快;
    • 代码更少(Lambda表达式);
    • 强大Stream API;
    • 便于并行;
    • 最大化减少空指针异常(OPtional类)。

    举例如下,JDK1.8的特性是不是与众不同。

    package com.xcbeyond.study.jdk8;
    
    import org.junit.Test;
    import java.util.Arrays;
    import java.util.List;
    
    /**
     * JDK1.8新特性
     * @Auther: xcbeyond
     * @Date: 2019/11/27 0027 23:53
     */
    public class Java8Test {
    
        @Test
        public void java8Example() {
            // 定义一个整型list,对其进行遍历
            Integer[] numArray={1,2,3,4,5,6,7,8};
            List<Integer> numList= Arrays.asList(numArray);
    
            /**
             * 方式1:常规foreach
             */
            for (int num : numList) {
                System.out.println(num);
            }
    
            /**
             * 方式2:JDK1.8 新特性写法(Lambda表达式)
             *  代码量是不是少了很多
             */
            numList.forEach((num) -> System.out.println(num));
        }
    }
    

    新特性

    JDK1.8新增了非常多的特性,本专题主要讨论以下几个:

    • Lambda表达式:Lambda允许把函数作为一个方法的参数(函数作为参数传递到方法中)。
    • 方法引用:方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
    • 默认方法:默认方法就是一个在接口里面有了一个实现的方法。
    • 新工具:新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps。
    • Stream API:新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
    • Date Time API:加强对日期与时间的处理。
    • Optional类:Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
    • Nashorn,JavaScript引擎:JDK1.8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。

    参考资料:

    1. https://www.oracle.com/technetwork/java/javase/8-whats-new-2157071.html
    2. https://www.runoob.com/java/java8-new-features.html
    展开全文
  • JDK1.8 新特性(全)

    2021-09-20 14:51:01
    JDK1.8 新特性 本文主要介绍了JDK1.8版本中的一些新特性,乃作者视频观后笔记,仅供参考。 jdk1.8新特性知识点: Lambda表达式 函数式接口 方法引用和构造器调用 Stream API 接口中的默认方法和静态方法 新时间日期...
  • JDK1.8新特性详细总结

    2022-01-12 10:55:36
    Oracle甲骨文公司于2015年1月15日发布了新一版JDK8,版本加入了许多特性。这些特性带来了一些改变,可以很大方便Java程序的编写。新特性主要涉及:对于JDK7中Fork/Join并行处理的升级;支持Lambda表达式;添加...
  • jdk1.8新特性.doc

    2020-04-01 13:23:33
    本文主要介绍了JDK1.8版本中的一些新特性,仅供参考。 jdk1.8新特性知识点: 1、Lambda表达式 2、函数式接口 3、方法引用和构造器调用 4、Stream API 5、接口中的默认方法和静态方法 6、新时间日期API
  • JDK1.8 新特性

    2021-12-28 13:44:12
    jdk1.8新特性知识点: Lambda表达式 函数式接口 *方法引用和构造器调用 Stream API 接口中的默认方法和静态方法 新时间日期API
  • JDK1.8究竟有哪些新特性
  • JDK1.8新特性

    2021-11-24 16:38:23
    二.JDK1.8新特性 3.1Lambda表达式 3.2Functional表达式 3.3方法引用和构造器引用 构造器引用 3.4.Stream API 3.5.Optional类 一.序言 Java8(又称为jdk1.8)是Java语言开发的一个主要版本。 Java8是oracle...
  • JDK1.8新特性知识详解

    2022-03-23 11:36:47
    jdk 1.8 新特性知识详解
  • jdk1.8 新特性

    2018-07-27 17:43:31
    1.8 新特性 1. 速度更快 – 红黑树 2. 代码更少 – Lambda 3. 强大的Stream API – Stream 4. 便于并行 – Parallel 5. 最大化减少空指针异常 – Optional
  • 方法的参数或局部变量类型是函数式接口(且仅一个抽象方法), @FunctionalInterface 函数式接口检验 1、Collections.sort(List list,Comparato c),根据上面的规则 2、用匿名内部类...
  • 5.ZonedDate,ZonedTime、ZonedDateTime : 带时区的时间或日期 用法和 LocalDate、 LocalTime、 LocalDateTime 一样 只不过ZonedDate,ZonedTime、ZonedDateTime 这三个带当前系统的默认时区 6. ZoneID 世界时区类...
  • JDK1.8新特性

    2021-04-30 13:23:22
    发现JDK1.8在集合中新增了Stream API功能,大大减少了代码量,提高了效率 目录1、分组2、筛选3、去重 下面说一下,常用的几个方法 1、分组 根据字段column将指定对象Obj的集合objList分组,转换为objMap,将字段作为...
  • jdk1.8版本的新特性

    千次阅读 2021-11-12 20:09:50
    的底层代码时,看见接口中方法的实现,在查阅资料后发现在jdk1.8版本增加了很多新特性,其中就接口中发法的实现。废话不多说关于jdk1.8新特性如下: Lambda表达式:Lambda允许把函数作为一个方法的参数(函数...
  • jdk1.8新特性总结

    2021-02-12 23:02:54
    1、default关键字在java里面,我们通常都是认为接口里面是只能抽象方法,不能任何方法的实现的,那么在jdk1.8里面打破了这个规定,引入了的关键字default,通过使用default修饰方法,可以让我们在接口里面定义...
  • jdk1.8 新特性.docx

    2020-05-27 14:58:55
    jdk1.8新特性知识点: Lambda表达式 函数式接口 *方法引用和构造器调用 Stream API 接口中的默认方法和静态方法 新时间日期API
  • JDK1.8新特性详解

    千次阅读 2021-03-13 22:21:18
    现在开发用的最多的就是jdk1.8;因为它具备很多优点: 1、速度更快 由于底层结构和JVM的改变,使得JDK1.8的速度提高。 2、代码更少(增加了的语法 Lambda 表达式) 增加新特性Lambda表达式的内部类改造,使得代码...
  • ​​​​​​​​​十分详细的jdk8时间相关操作以及知识点(文章很长) LocalDateTime工具类:根据当前、周、月、季度、半年、年等维度获取时间 二、常用 /** * <p>获取当前月的范围内的所有时间<p>...
  • jdk1.8新特性

    2022-05-12 12:53:47
    文章目录jdk1.8新特性一、 Lambda 表达式二、 方法引用三、函数式接口四、 接口允许定义默认方法和静态方法五、Stream API六、日期/时间类改进七、Optional 类八、 Java8 Base64 实现 jdk1.8新特性 一、 ...
  • 注意:Lambda中必须个接口 三、Lambda的形式 使用 Lambda 时,实现方法可以参数,也可以返回值,如果没指定参数类型,则由编译器自行推断得出。 3.1、 无参带返回值 生成[1,10]之间的任意整数 interface ...
  • JDK1.8 的 8 个新特性

    千次阅读 2022-02-22 16:01:39
    jdk1.8 的一些新特性简化了代码的写法,减少了部分开发量。主要如下: Lambda 表达式 接口中的默认方法和静态方法 函数式接口 方法引用和构造器调用 局部变量限制 Stream API 新时间日期API 二、default 关键字 在...
  • jdk1.8新特性--Stream流

    2022-03-27 20:06:22
    1.8新特性中,我们避无可避的一个就是流,他可以让我们对集合更方便的处理,并且看起来更直观 很多人觉得Stream流可以做到的事情,for循环一样可以,为什么还要学并致用. 速度方面,其实Stream流与for循环基本一直,但是...
  • JDK1.8新特性总结

    万次阅读 多人点赞 2018-08-07 14:50:29
    背景: 因为面试被问到了,而且一直以来想去深入了解一下JDK 1.8的新特性 。才发现其实好多已经用在了项目中,自己没能察觉,所以总结一下...在jdk1.8中对hashMap等map集合的数据结构优化。 原来的hashMap采用的数...
  • jdk1.8新特性: 1.Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可。 2.新增lambda表达式 3.提供函数式接口 4.Java 8 允许你使用关键字来传递方法或者构造函数引用 5.我们可以直接在...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 63,417
精华内容 25,366
关键字:

jdk1.8的新特性有哪些