我的Java笔记

  本篇博文主要讲博主在学习Java上的一些常用知识,内容涉及J2SEJ2EE。写作主要目的是方便自己查看巩固,当然也借此机会可以与其他人在学习上有一个相互交流的机会,有些笔记可能看起来理所当然,但是依然觉得有必要记录一下。
  本文采取持续更新策略,但更新周期不定

集合与数组

根据数组来创建List

以字符串数组为例:

    String[] arr = {"Reka", "Downey", "Leakey"};
    List<String> list = Arrays.asList(arr);

  以上创建的List不可添加或删除容器中的元素,因为通过Arrays.asList创建的ArrayList实际上是Arrays中的一个私有静态类,并不是传统意义上的java.util.ArrayList;如果需要往容器中添加或者删除元素,必须将生成的List进一步封装成java.util.ArrayList
  注:在创建字符串数组arr时使用的是JDK5及以上的特性:一个花括号{}代表一个一维数组,花括号嵌套时为多维数组。 

    List<String> list = new ArrayList<>(Arrays.asList("Reka", "Downey", "Leakey"));

根据List来创建数组:

        List<String> list = Arrays.asList("A", "B", "C");
        String[] arr = (String[]) list.toArray(); // 运行正常
        list = new ArrayList<String>(list);
        arr = (String[]) list.toArray(); // 运行时抛出 java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;

  Arrays.ArrayList是直接调用clone方法将数组转成List,而java.util.ArrayList则是委托给ArrayscopyOf方法,两者的实现不同导致结果不同(具体得看源码),为了确保转换的正确性,我们应该按下面这种方式进行转换:

        List<String> list = Arrays.asList("A", "B", "C");
        String[] arr = new String[list.size()];
        arr = list.toArray(arr); // 运行正常

        list = new ArrayList<String>(list);
        arr = new String[list.size()];
        arr = list.toArray(arr); // 运行正常

  虽然实际上在调用List.toArray(T[] arr)可以不需要赋值给arr,但是为了保证安全与正确,最好还是将其回赋给arr(因为当arr的容量与List的容量不等时返回的是一个新的数组),具体看源码。


在遍历List时移除其中的元素

使用foreach

        List<String> list = new ArrayList<>(Arrays.asList("Reka", "Downey", "Leakey"));

        for (String s : list) {
            if ("Reka".equals(s)) {
                list.remove(s);
            }
        }

  此时在执行remove操作的时候将抛出java.util.ConcurrentModificationException异常,下面看看使用JDK8流式API进行操作:

        List<String> list = new ArrayList<>(Arrays.asList("Reka", "Downey", "Leakey"));
        list.stream().filter("Reka"::equals).forEach(list::remove);

  此时依然将抛出ConcurrentModificationException异常,但是,如果元素Reka并不在集合中的时候,上述两者都将不会抛出异常,正确的移除方式应该是通过Iterator迭代器实现以确保安全:

        List<String> list = new ArrayList<>(Arrays.asList("Reka", "Downey", "Leakey"));
        Iterator<String> stringIterator = list.iterator();
        while (stringIterator.hasNext()) {
            String s = stringIterator.next();
            if ("Reka".equals(s)) {
                stringIterator.remove();
            }
        }

  此时才能正确移除容器中的Reka元素。注意:以上的情况都没有考虑多线程情况,在多线程情况下,List也要做相应的修改以适应多线程访问。

2016-09-06.jpg


反射

检测类中的某个字段是否是常用类型

(个人对常用类型的定义为:基础数据类型及其包装类、String):

import java.lang.reflect.Field;

/**
 * @author : Chung Junbin
 * @email : <a href="mailto:rekadowney@163.com">发送邮件</a>
 * @createDate : 2016-09-06 16:10
 * @description :
 */
public class FieldTypeConsultant {


    public static boolean isPrimitive(Field field) {
        return field.getType().isPrimitive();
    }

    public static boolean isWrapped(Field field) {
        Field type = null;
        try {
            type = field.getType().getDeclaredField("TYPE");
        } catch (NoSuchFieldException ignored) {
            // 没有这个字段则表示不是基础数据类型的包装类型
        }
        return type != null;
    }

    public static boolean isCommonType(Field field) {
        return field.getType() == String.class || isPrimitive(field) || isWrapped(field);
    }

}

另一种比较简单粗暴的做法是:

import java.lang.reflect.Field;

/**
 * @author : Chung Junbin
 * @email : <a href="mailto:rekadowney@163.com">发送邮件</a>
 * @createDate : 2016-09-06 21:49
 * @description :
 */
public class CurtFielTypeConsultant {

    private static final Class[] primitiveClasses = {char.class, boolean.class, byte.class,
            short.class, int.class, long.class, float.class, double.class/*, void.class*/};

    private static final Class[] wrappedClasses = {Character.class, Boolean.class, Byte.class,
            Short.class, Integer.class, Long.class, Float.class, Double.class/*, Void.class*/};

    public static boolean isPrimitive(Field field) {
        Class<?> typeOfField = field.getType();
        for (Class<?> clazz : primitiveClasses) {
            if (clazz == typeOfField) {
                return true;
            }
        }
        return false;
    }

    public static boolean isWrapped(Field field) {
        Class<?> typeOfField = field.getType();
        for (Class<?> clazz : wrappedClasses) {
            if (clazz == typeOfField) {
                return true;
            }
        }
        return false;
    }

    public static boolean isCommonType(Field field) {
        return field.getType() == String.class || isPrimitive(field) || isWrapped(field);
    }

}

  两种效果一致,但个人更加推崇第一种方式。

2016-09-06.jpg


类路径下文件读写

读写类路径下的文件(配置文件和class文件)

有如下目录结构

src
 └──main
       ├──java
       └──resources
               │   log4j.properties
               │
               └──bundle
                       db.properties

提供文件检索类FielRetrieval

import java.io.File;
import java.net.URL;
import java.util.Optional;

/**
 * @author : Chung Junbin
 * @email : <a href="mailto:rekadowney@163.com">发送邮件</a>
 * @createDate : 2016-09-07 10:03
 * @description :
 */
public class FileRetrieval {

    /**
     * <p>读取 classpath 下的文件</p>
     * <pre>
     *   例如:目录结构为:
     *          src
     *              main
     *                  resources
     *                      bundle
     *                          db.properties
     *                      log4j.properties
     *   那么读取 log4j.properties 应该传入 {@code log4j.properties} 作为参数;而读取
     * db.properties 则应该传入 {@code bundle/db.properties}
     * </pre>
     *
     * @param filename 文件名称(包括目录)
     * @return 文件本身
     */
    public static Optional<File> ofFilename(String filename) {
        URL url = FileRetrieval.class.getClassLoader().getResource(filename);
        if (url == null) {
            return Optional.empty();
        }
        File file = new File(url.getFile());
        return Optional.of(file);
    }

}

附:FileRetrieval.class.getClassLoader().getResource(filename)FileRetrieval.class.getResource('/' + filename) 是等效的;该类放在src/main/java下则只能读写src/main/resources下的配置文件和src/main/java生成的类文件;反之放在src/test/java下则只能读写src/test/resources下的配置文件和src/test/java生成的类文件

当然:如果仅仅是读取properties文件,那么还有一种更加方便快捷的方式:

        ResourceBundle log4jResourceBundle = ResourceBundle.getBundle("log4j");
        ResourceBundle dbResourceBundle = ResourceBundle.getBundle("bundle/db");
        System.out.println(dbResourceBundle.getString("mysql.username"));

注:ResourceBundle传入的是basenamebasename是不包括文件扩展名的。

2016-09-07.jpg


字符编码

  这里扯一下软件安装的事情:安装软件的时候,博主会尽量首选软件的压缩包而不是安装包,因为安装包有可能自动添加了一些环境变量,而且一不小心就有可能安装在默认路径上了,这样对软件管理相当不方便;博主更习惯创建一个存放所有软件的根目录,在软件根目录内部按照类别创建第二级目录,之后再根据那些软件定位到各自所属的科目下(文档、音乐、视频等都差不多一个模式)。
  第二:软件安装完毕之后,第一次打开软件时,建议找到PreferenceOptionsSettings等可以修改参数的菜单,之后一个个菜单看,将所有的字符编码都设置为UTF-8,另外还可以设置一些首选下载目录、关闭自动生成备份文件功能等等。例如:我在安装IDEA的时候宁愿花半个甚至一个、两个小时的时间将全局配置与项目配置的菜单项都看一遍,接着修改字符编码,修改默认Java编译器、添加SVNGit支持、导入GitHub账户、指定Maven路径、指定Tomcat路径、配置字体(首选等宽字体)、修改文件模板、关闭不必要的插件等等一系列内容。
  好了,有些偏题了。
  在编程中用到字符编码的时候,博主首选的是JDK7及以上的StandardCharsets.UTF_8StandardCharsets是一个final修饰的类,该类存放了六种在任何Java平台上都保证可以使用的标准字符集。分别是UTF-8US-ASCIIISO-8859-1UTF-16BEUTF-16LEUTF-16。首推当然是UTF-8,其次是在网络传输中有时得用到的ISO-8859-1
  这样以后使用字符集的时候就应该尽量选择可以接收Charset的重载方法而不是使用接收字符集名称的方法。比如:

        String message = "Message";
        byte[] utf8 = message.getBytes("UTF-8"); // 不推荐,需要捕获异常
        utf8 = message.getBytes(StandardCharsets.UTF_8); // 推荐

  注:通过Charset.availableCharsets();可以得到平台支持的字符集名称以及他们对应的字符集。

2016-09-07.jpg


原创声明:
本文为个人原创,如有错误与不妥,欢迎提出!
另外,未经许可,谢绝转载。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
org.bouncycastle.openssl.PEMException: problem parsing ENCRYPTED PRIVATE KEY: java.lang.SecurityException: JCE cannot authenticate the provider BC at org.bouncycastle.openssl.PEMReader$EncryptedPrivateKeyParser.parseObject(Unknown Source) at org.bouncycastle.openssl.PEMReader.readObject(Unknown Source) at org.whispersystems.textsecuregcm.push.RetryingApnsClient.initializePrivateKey(RetryingApnsClient.java:135) at org.whispersystems.textsecuregcm.push.RetryingApnsClient.(RetryingApnsClient.java:65) at org.whispersystems.textsecuregcm.push.APNSender.(APNSender.java:61) at org.whispersystems.textsecuregcm.WhisperServerService.run(WhisperServerService.java:182) at org.whispersystems.textsecuregcm.WhisperServerService.run(WhisperServerService.java:111) at io.dropwizard.cli.EnvironmentCommand.run(EnvironmentCommand.java:43) at io.dropwizard.cli.ConfiguredCommand.run(ConfiguredCommand.java:87) at io.dropwizard.cli.Cli.run(Cli.java:78) at io.dropwizard.Application.run(Application.java:93) at org.whispersystems.textsecuregcm.WhisperServerService.main(WhisperServerService.java:283) Caused by: java.lang.SecurityException: JCE cannot authenticate the provider BC at javax.crypto.Cipher.getInstance(Cipher.java:656) at javax.crypto.Cipher.getInstance(Cipher.java:595) ... 12 more Caused by: java.util.jar.JarException: file:/opt/code/signal-Server-master/target/TextSecureServer-1.87.jar has unsigned entries - org/whispersystems/dispatch/DispatchManager$4.class at javax.crypto.JarVerifier.verifySingleJar(JarVerifier.java:502) at javax.crypto.JarVerifier.verifyJars(JarVerifier.java:363) at javax.crypto.JarVerifier.verify(JarVerifier.java:289) at javax.crypto.JceSecurity.verifyProviderJar(JceSecurity.java:164) at javax.crypto.JceSecurity.getVerificationResult(JceSecurity.java:190) at javax.crypto.Cipher.getInstance(Cipher.java:652) ... 13 more --------------------- 作者:idwtwt 来源:CSDN 原文:https://blog.csdn.net/idwtwt/article/details/83793940 版权声明:本文为
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值