JAVA SE 8 学习笔记(六)杂项改进

来源:互联网 发布:淘宝旺铺免费模板 编辑:程序博客网 时间:2024/05/21 19:22

1. 字符串

String提供了一个与split相反的join方法,将字符串通过分隔符组合起来.字符串可以来自于Array或者Iterable<? extends CharSequence>:

String joined = String.join("/", "usr", "local", "bin"); // "usr/local/bin"System.out.println(joined);String ids = String.join(", ", ZoneId.getAvailableZoneIds());System.out.println(ids);// All time zone identifiers, separated by commas

2. 数字类

7种数字类型的包装类提供了BYTES字段,用来表示该类型的长度

8种原始类型的包装类型,提供了静态的hashCode方法,用来返回与实例方法相同的hash码,省去装箱/拆箱。


Short, Integer, Long, Float, 和 Double提供了sum、max和min,用来在流操作中作为聚合函数使用。Boolean包含了logicalAnd, logicalOr, 和 logicalXor


Integer现在支持无符号数学计算, Byte 和 Short 类增加方法 toUnsignedInt

Byte, Short, 和 Integer 增加方法 toUnsignedLong.

使用无符号数字,会丢失负数,并获得两倍的正数范围

Integer 和 Long 添加方法 compareUnsigned, divideUnsigned, 和
remainderUnsigned
(求余)用来处理无符号值


Float和Double新增静态方法isFinite.当数字为正/负无穷大或者NAN(非数字时),该方法返回false,否则返回true


BigInteger 添加实例方法 (long|int|short|byte)ValueExact
返回对应的值, 当值不再目标范围内时抛出 ArithmeticException


3. 数学函数

Math类新增方法为:(add|subtract|multiply|increment|decrement|negate)Exact,参数为 int 和 long.这些方法可以进行精确计算,如果超过范围则会抛出异常。例如100000*100000会计算出错误结果1410065408(int型overflow),而multiplyExact(100000, 100000)会抛出异常。


floorMod floorDiv旨在解决整型余数问题。在java中,如果n为负数,n%2为-1,而floorMod(position + adjustment, 12)总是返回一个0到11之间的数字。(对于负的除数,还是会返回负值)。floorDiv则返回0到12之间的数字。


4. 集合

1.集合接口新增方法参照下表:



2. 比较器

Comparator接口新增了许多有用的方法。

comparing可以接收一个键提取器。可以使用thenComparing来组合多个键提取器(按顺序排序)

Arrays.sort(people,Comparator.comparing(Person::getLastName).thenComparing(Person::getFirstName));

也可以为提取的键指定一个比较器

Arrays.sort(people, Comparator.comparing(Person::getName,(s, t) -> Integer.compare(s.length(), t.length())));

两个方法都有避免装箱拆箱的形式,例如:

Arrays.sort(people, Comparator.comparingInt(p -> p.getName().length()));

如果键函数包含Null,可以使用Comparator.nullFirst/nullLast方法决定null的位置

Comparator.comparing(Person::getMiddleName(), Comparator.nullsFirst(...))

静态方法reverseOrder可以得到相反的排序。要点到任意比较器,可以调用实例方法reversed。


5. 使用文件

1.读取文件行的流

为了延迟读取一个文件中的行,可以使用Files.lines方法,它会产生一个包含字符串的流,每个字符串就是文件的一行

Stream<String> lines = Files.lines(path);Optional<String> passwordEntry = lines.filter(s -> s.contains("password")).findFirst();

一旦包含password的第一行被找到,剩下的行就不会再被读取

Files.lines方法默认UTF-8编码。也可以设置charset来指定编码

Steam接口继承了AutoClosable,因此可以使用try-with-resources语法

当一个流调用其它流时,close方法也会递归调用

try (Stream<String> filteredLines= Files.lines(path).filter(s -> s.contains("password"))) {Optional<String> passwordEntry = filteredLines.findFirst();...}

如果希望流关闭时收到通知,可以附加一个onClose方法

try (Stream<String> filteredLines= Files.lines(path).onClose(() -> System.out.println("Closing")).filter(s -> s.contains("password"))) { ... }
如果流读取文件发生IOException,则会包装异常为UncheckedIOException抛出


如果希望按行读取文件以外的来源,可以考虑使用BufferedReader.lines方法

try (BufferedReader reader= new BufferedReader(new InputStreamReader(url.openStream()))) {Stream<String> lines = reader.lines();...}

注意:在这段代码中,关闭Steam并不会关闭Reader,因此需要将Reader放在try语句的头部

------------------------------------------------------------------


2. 遍历目录项的流

Files.list可以返回一个指定目录中项目的Steam<Path>对象

由于读取目录会涉及关闭一个系统资源,因此需要使用try语句

try (Stream<Path> entries = Files.list(pathToDirectory)) {...}

list方法不会进入子目录,要处理目录下的所有子目录,应该使用Files.walk方法

try (Stream<Path> entries = Files.walk(pathToRoot)) {// Contains all descendants, visited in depth-first order}
可以使用Files.walk(pathToRoot, depth)来指定访问目录树的深度

如果打算根据指定条件过滤walk方法的结果,应该使用find方法来代替,参数为一个predicate函数,参数为路径和一个BasicFileAttributes对象.find方法效率较高


-------------------------------------------------------


3. Base64编码

关于Base64编码的概念,请参照:http://blog.csdn.net/flycct/article/details/51445966

要进行Base64编码。可以使用Base64类的静态方法getEncodergetUrlEncoder, 或者getMimeEncoder

该类包含了堆bytes数组或者NIO ByteBuffer进行编码的方法

Base64.Encoder encoder = Base64.getEncoder();String original = username + ":" + password;String encoded = encoder.encodeToString(original.getBytes(StandardCharsets.UTF_8));


也可以包装一个输出流,所有发送给它的数据都会自动进行编码

Path originalPath = ..., encodedPath = ...;Base64.Encoder encoder = Base64.getMimeEncoder();try (OutputStream output = Files.newOutputStream(encodedPath)) {Files.copy(originalPath, encoder.wrap(output));}
如果要进行解码,只需要将这些操作颠倒过来

Path encodedPath = ..., decodedPath = ...;Base64.Decoder decoder = Base64.getMimeDecoder();try (InputStream input = Files.newInputStream(encodedPath)) {Files.copy(decoder.wrap(input), decodedPath);}

如果是使用基本的编码器,那么输出可能会包含反斜线“/”字符,但是如果使用URL编码器,那么输出的内容对URL来说是安全的。

MIME编码器会使用基本的字母数字产生BASE64输出,而且对MIME格式友好:每一行输出不超过76个字符,而且每行以“\r\n”符结束

参照博文:http://blog.csdn.net/chszs/article/details/17027649


6. 注解

1. JAVA SE 8允许可重复注解,实装内容包括两点:

1)将注解标注为@Repetable

2)提供一个容器主机

例如:

@Repeatable(TestCases.class)@interface TestCase {String params();String expected();}@interface TestCases {TestCase[] value();}
重复注解的使用:

@TestCase(params="4", expected="24")@TestCase(params="0", expected="1")public static long factorial(int n) { ... }
当用户提供多个@TestCase注解时,它们会自动包装为@TestCases注解

在表示factorial方法的元素上调用element.getAnnotation(TestCase.class)时返回为null

element.getAnnotationsByType(TestCase.class)则会返回包含TestCse注解的数组

---------------------------------------------------------------------------------


2. 可用于类型的注解

Java8中,可以在任何类型上标注注解

例如:

• 泛型类型参数: List<@NonNull String>, Comparator.<@NonNull String>reverseOrder().


• 用于array声明的任何位置: @NonNull String[][] words (words[i][j] is not null),

String @NonNull [][] words (words is not null), String[] @NonNull [] words (words[i] is

not null).


•父类和接口: class Image implements
@Rectangular Shape.


• 构造函数调用: new @Path String("/usr/bin").


• 类型转换和Instance of检查: (@Path String) input, if (input instanceof @Path String).


•定义抛出的异常: public Person read() throws @Localized IOException.


• 用于通配符和类型绑定: List<@ReadOnly ? extends Person>, List<? extends @ReadOnly> Person.


• 用于方法和构造函数引用: @Immutable Person::getName.


也有一些地方不能使用注解

@NonNull String.class // 错误,不能标注class
import java.lang.@NonNull String; // 错误,不能标注import

另外,不能在注解上再加注解


推荐注解工具框架:

Checker Framework: http://types.cs.washington.edu/checker-framework/tutorial

---------------------------------------------------------------------------------


3. 方法参数反射

通过java.lang.reflect.Parameter类可以获取参数的名字,这样在某些参数名称与注解相同的情况下,可以将他们统一起来,省略代码

例如:

Person getEmployee(@PathParam("dept") Long dept, @QueryParam("id") Long id)
可以省略为以下代码,而通过参数名字来获取注解的value

Person getEmployee(@PathParam Long dept, @QueryParam Long id)
不幸的是,为了获取文件中的信息,必须使用javac -parameters SourceFile.java的方式来编译源码


7. 其他

1.Null检查

Objects类新增两个静态的predicate方法,isNull和nonNull

这两个方法非常实用,例如:

steam.anyMatch(Objects::isNull);  // 检查是否存在null

steam.filter(Objects::nonNull); // 获取所有非null对象


2. 正则表达式

命名捕获组  Matcher类的startendgroup方法,支持使用组名:

Pattern pattern = Pattern.compile("^(?<year>\\d{4})-(?<month>\\d{2})-\\d{2}$");Matcher matcher = pattern.matcher("2016-05-25");if(matcher.matches()) {System.out.println(matcher.group("month"));System.out.println(matcher.start("month"));System.out.println(matcher.end("month"));}

执行结果

05
5
7


Patten类增加splitAsStream方法,将一个CharSequence正则表达式进行分隔

Stream<String> words = Pattern.compile("\\d").splitAsStream("a1b2c3");words.forEach(v -> System.out.println(v));
执行结果

a
b
c

asPredicate方法,可以用来过滤匹配的字符串

Stream<String> words = Pattern.compile("\\d").splitAsStream("a1b2c3");words.filter(Pattern.compile("[bc]").asPredicate()).forEach(v -> System.out.println(v));
执行结果

b
c


0 1
原创粉丝点击