Java中的一些奇淫技巧总结
2015-04-12 10:36
288 查看
不用中间变量交换两个数
public class SWapTest { static int a = Integer.MAX_VALUE; static int b = 1; public static void main(String[] args) { System.out.println("初始值,a = " + a + ",b = " + b); int temp = a; a = b; b = temp; System.out.println("中间变量交换,a = " + a + ",b = " + b); a = a ^ b; b = a ^ b; a = a ^ b; System.out.println("异或交换,a = " + a + ",b = " + b); a = a + b; System.out.println(a); // 溢出 b = a - b; a = a - b; System.out.println("求和交换,a = " + a + ",b = " + b); } }
用异或能够实现两个数之间的交换主要是异或具有如下的性质:
任意一个变量X与其自身进行异或运算,结果为0,即X^X=0。
任意一个变量X与0进行异或运算,结果不变,即X^0=X。
异或运算具有可结合性,即a^b^c=(a^b)^c=a^(b^c)。
异或运算具有可交换性,即a^b=b^a。
第一步:a = 原来的a ^ b;
第二步:b = 原来的a ^ b ^ b = 原来的a(b已经得到了交换);
第三步:a = 原来的a ^ b ^ 原来的a = b。(a和b都得到交换)。
如何更好地打印数组中的内容
我们知道如果直接打印数组名,将会打印其hash码。如何漂亮地显示数组中的内容?——使用java.util.Arrays.toString()方法。public class ArrayTest { public static void main(String[] args) { int[] a = { 1, 2, 3, 4, 5, 6, 7, 8 }; // a = null; System.out.println(Arrays.toString(a)); printArray(a); } /** * 以良好的格式输出数组中的内容,和Arrays.toString()方法类似 * @param arr */ private static void printArray(int[] arr){ if (arr==null) { System.out.println("null"); return; } System.out.print("["); for (int i = 0; i < arr.length; i++) { if (i!=arr.length-1) { System.out.print(arr[i] + ", "); }else { System.out.println(arr[i] + "]"); } } } }
解决Eclipse中项目的乱码问题
中文机器上,Eclipse默认的项目编码时GBK,如果我们将其导出到
UTF-8编码的机器上就会出现乱码。使用JavaIO中的
InputStreamReader和
OutputStreamWriter这两个类可以完成文件编码的转换。(这两个类的构造方法中可以指定字符集)。基于此,写出如下的Java小程序,可以将指定目录下的
GBK编码的Java源文件转换成
UTF-8编码。
public class FileUtil { /** * 过滤当前目录下的特定后缀名的文件,并将文件名保存到字符串中 不同文件名之间以逗号分隔 * @fileName :文件名或者目录名 * @filter :过滤器,特定的后缀,*或者空字符串表示匹配所有 */ static StringBuilder result = new StringBuilder(); static int count = 0; private static String getJavaFiles(String fileName, String filter) { File file = new File(fileName); if (filter == null || filter.equals("*")) { filter = ""; } if (file.isFile() && file.getName().endsWith(filter)) { result.append(file.getAbsolutePath() + ","); count++; } if (file.isDirectory()) { File[] files = file.listFiles(); for (File f : files) { getJavaFiles(f.getAbsolutePath(), filter); } } return result.toString(); } /** * @param file:需要转换的文件名 * @param fromCharset:文件的原始编码 * @param toCharset:需要转换的编码 */ private static boolean convertEncoding(File file, String fromCharset, String toCharset) { try { InputStreamReader isr = new InputStreamReader(new FileInputStream( file), fromCharset); File tempFile = new File("tmp"); OutputStreamWriter oos = new OutputStreamWriter( new FileOutputStream(tempFile), toCharset); int temp = 0; while ((temp = isr.read()) != -1) { oos.write(temp); } isr.close(); oos.close(); isr = new InputStreamReader(new FileInputStream(tempFile)); oos = new OutputStreamWriter(new FileOutputStream(file)); while ((temp = isr.read()) != -1) { oos.write(temp); } isr.close(); oos.close(); tempFile.deleteOnExit(); // 删除临时文件 return true; } catch (FileNotFoundException e) { e.printStackTrace(); return false; } catch (IOException e) { e.printStackTrace(); return false; } } public static void main(String[] args) { String fileString = getJavaFiles("目录名", "*"); String[] fileNames = fileString.split(","); for (String filename : fileNames) { if (convertEncoding(new File(filename), "gbk", "utf-8")) { System.out.println(filename + "转换成功!"); } } } }
关于JavaIO更多的操作,详见:http://git.oschina.net/gaopengfei/JavaUtil/blob/master/src/org/gpf/FileHelper.java
关于3目运算符
3目运算符存在自动类型提升,例如以下的代码:char ch = 'A'; System.out.println(true?ch:65535); // 输出字符'A' System.out.println(true?ch:65536); // 输出ASCII 65 int number = 0; System.out.println(true?ch:0); // 输出字符'A' System.out.println(true?ch:number); // 输出ASCII 65
java中的字符采用的是UTF-8编码,每一个字符采用2个字节表示,范围从\u0000~\uffff即0~65535.
关于除0问题
整数除以0会发生除零异常,但是浮点数除以0不会发生除零异常,而是输出无穷大。System.out.println(1.0 / 0); // 输出Double中定义的Infinity System.out.println(1 / 0.0); // 输出Double中定义的Infinity System.out.println(1 / 0); // 抛出算术异常
TreeSet集合问题
添加到TreeSet中的元素必须实现Comparable接口。TreeSet底层的实现是二叉树。通过覆写
compareTo()方法我们可以自己指定元素在此集合中的位置。
class Student implements Comparable<Student> { private String name; private int age; public Student(String name, int age) { this.name = name; this.age = age; } @Override public int compareTo(Student s) { // 按照年龄升序排列,如果年龄相同则按照姓名升序排列 int tmp = Integer.valueOf(age).compareTo(Integer.valueOf(s.age)); if (tmp == 0) return name.compareTo(s.name); return tmp; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } } public class TreeSetTest { public static void main(String[] args) { TreeSet<Student> treeSet = new TreeSet<Student>(); treeSet.add(new Student("a", 14)); treeSet.add(new Student("c", 12)); treeSet.add(new Student("z", 12)); treeSet.add(new Student("g", 16)); treeSet.add(new Student("B", 1)); treeSet.add(new Student("q", 17)); treeSet.add(new Student("B", 1)); // 无法加入 System.out.println(treeSet); } }
以上程序的运行结果是先按照年龄升序,如果年龄相同则按照姓名升序。年龄和姓名均相同就会被认为是同一个人而无法加入。
TreeSet集合使用二叉树数据结构存储元素(二叉排序树【小于0的元素放在左子树,大于0的元素放在右子树,等于0的元素(认为元素相等)不会加入到树中】完全依赖于compareTo方法的返回值)。每次向TreeSet集合中加入元素都要与根元素比较,如果比根元素小就递归比较左子树,否则递归比较右子树,直到该元素找到正确的插入位置或者被树拒绝。TreeSet取得元素是先序遍历(从小到大)。
了解了TreeSet的工作原理,下面就可以使用TreeSet来实现插入顺序和输出顺序一致和以插入顺序的逆序输出。
// 向TreeSet中加入的顺序是什么,则输出的顺序就是什么 @Override public int compareTo(Student s) { return 1; } // 向TreeSet中加入的顺序是什么,则输出的顺序就是它的逆序 @Override public int compareTo(Student s) { return -1; } // 只会保留第一个元素。以后的元素因为和根元素比较compareTo结果是0,所以不会加入到树 @Override public int compareTo(Student s) { return 0; }
以上的排序依靠的元素自身的
compareTo()方法的返回值,也叫做元素自身的顺序。TreeSet集合中的元素需要实现
Comparable接口。但是此时我们不希望采用元素默认的比较器或者元素没有实现
Comparable接口,可以在创建TreeSet容器的时候,让容器自身具备比较性。
class Student implements Comparable<Student> { String name; int age; public Student(String name, int age) { this.name = name; this.age = age; } @Override public int compareTo(Student s) { // 按照年龄升序排列,如果年龄相同则按照姓名升序排列 int tmp = Integer.valueOf(age).compareTo(Integer.valueOf(s.age)); if (tmp == 0) return name.compareTo(s.name); return tmp; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } } public class TreeSetTest { public static void main(String[] args) { /** * 不使用元素自身的比较器,在创建集合的时候指定我们自己的比较器 */ TreeSet<Student> treeSet = new TreeSet<Student>( new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { // 按照姓名为第一排序字段,第二排序字段为age,如果name和age都相同则认为是同一个人不会加入树 int temp = o1.name.compareTo(o2.name); if (temp == 0) return o1.age - o2.age; return temp; } }); // TreeSet<Student> treeSet = new TreeSet<Student>(); treeSet.add(new Student("a", 14)); treeSet.add(new Student("c", 12)); treeSet.add(new Student("z", 12)); treeSet.add(new Student("g", 16)); treeSet.add(new Student("B", 1)); treeSet.add(new Student("q", 17)); treeSet.add(new Student("B", 1)); System.out.println(treeSet); } }
利用以上思想我们可以实现String的按照字符串的长度进行排序(注意:不要忘记次要关键字)。
public class TreeSetTest { public static void main(String[] args) { TreeSet<String> treeSet = new TreeSet<String>(new Comparator<String>() { @Override public int compare(String o1, String o2) { int temp = o1.length() - o2.length(); if (temp == 0) return o1.compareTo(o2); return temp; } }); treeSet.add("Ac"); treeSet.add("C"); treeSet.add("AD"); treeSet.add("Adsf"); treeSet.add("sdfds"); treeSet.add("bg"); System.out.println(treeSet); } }
使用java语言描述以下的一种场景
一个公司有多个部门,一个部门有多名员工。这是典型的一对多关系,可以使用集合的嵌套来解决。首先建立员工实体类。
public clas fad9 s Employee { int age; String name; public Employee(int age, String name) { super(); this.age = age; this.name = name; } @Override public String toString() { return "Employee [age=" + age + ", name=" + name + "]"; }; }
每个部门的名称和部门是一一映射可以用Map来描述,而一个部门有多个员工可以使用List集合来描述。
public static void main(String[] args) { Map<String, List<Employee>> enterprise = new HashMap<String, List<Employee>>(); // 公司 List<Employee> deptFinancial = new ArrayList<Employee>(); // 财务部 List<Employee> deptPerson = new ArrayList<Employee>(); // 人事部 deptFinancial.add(new Employee(12, "张三")); deptFinancial.add(new Employee(13, "李四")); deptFinancial.add(new Employee(14, "王五")); deptPerson.add(new Employee(18, "赵六")); deptPerson.add(new Employee(28, "孙七")); enterprise.put("人事部", deptPerson); enterprise.put("财务部", deptFinancial); for (Map.Entry<String, List<Employee>> entry : enterprise.entrySet()) { System.out.println("部门名称:" + entry.getKey()); getEmployeeInfo(entry.getValue()); } } private static void getEmployeeInfo(List<Employee> employees) { for (Employee employee : employees) { System.out.println(employee); } }
集合工具类java.util.Collections
类的妙用
逆序输出TreeSet集合中的内容
java.util.Collections.reverseOrder()方法将可以将一个已经存在的比较器强行逆转。
public class CollectionsTest { public static void main(String[] args) { TreeSet<String> set = new TreeSet<String>(); addAndPrintElements(set); // 方案一:在创建容器的时候指定一个比较器(因为此处String为final类型无法覆写compareTo方法) set = new TreeSet<String>(new Comparator<String>() { @Override public int compare(String o1, String o2) { return o2.compareTo(o1); } }); addAndPrintElements(set); // 方案二:使用java.util.Collections.reverseOrder()方法将比较器强行逆转 set = new TreeSet<String>(Collections.reverseOrder()); addAndPrintElements(set); // 按照字符串的长度升序排列 set = new TreeSet<String>(new StrLenComparator()); addAndPrintElements(set); // 将自定义的字符串长度比较器强行逆转实现长度降序排列 set = new TreeSet<String>(Collections.reverseOrder(new StrLenComparator())); addAndPrintElements(set); } /** * @param set */ private static void addAndPrintElements(TreeSet<String> set) { set.add("c"); set.add("aaa"); set.add("asas"); set.add("bg"); set.add("dcdss"); set.add("dcc"); System.out.println(set); } } class StrLenComparator implements Comparator<String> { @Override public int compare(String o1, String o2) { int temp = o1.length() - o2.length(); if (temp == 0) return o1.compareTo(o2); return temp; } }
使用Collections的synchronizedXXX
方法得到同步的集合操作
查看该方法的源码,发现SynchronizedXXX是
Collections的静态内部类,该静态内部类的一系列方法中封装了一系列的同步操作,该操作是使用静态代码块实现的。
使用Collections的swap(List<?> list, int i, int j)
方法可以交换List集合中特定角标的2个元素
List<String> list = new ArrayList<String>(); list.add("a"); list.add("b"); list.add("c"); list.add("d"); System.out.println(list); Collections.swap(list, 1, 3); // 交换索引为1和3的元素 System.out.println(list);
使用Collections的shuffle方法随机置换List集合中的元素
List<String> list = new ArrayList<String>(); list.add("a"); list.add("b"); list.add("c"); list.add("d"); System.out.println(list); Collections.shuffle(list); // 打乱List集合中的元素 System.out.println(list);
PS:以上的例子可以用于扑克牌洗牌或者游戏的骰子。
Arrays.asList()
方法使用的注意点
数组变成集合是为了便于使用集合的方法。不能向数组转化的集合中增加或者删除元素,会抛出
UnsupportedOperationException。
String[] arr = {"abc","bbc","kss","jack"}; List<String>list = Arrays.asList(arr); System.out.println("arr中包含abc?" + list.contains("abc")); list.add("hello"); // 不能像数组转化的集合中增加或者删除元素 list.remove(0); // 不能像数组转化的集合中增加或者删除元素`
java.util.Collection
接口中的toArray()
方法可以将集合中的元素转化为数组。
集合变成数组是为了限制对元素的操作(不能增删)。注意:数组的长度传入0即可,不需要指定长度避免内存浪费。
List<String> list = new ArrayList<String>(); list.add("abc"); list.add("ggg"); list.add("kkk"); String[] arr = list.toArray(new String[0]); // 不需要指定创建的数组的长度,直接传入0即可 System.out.println(Arrays.toString(arr)); arr = list.toArray(new String[5]); System.out.println(Arrays.toString(arr)); // 有2个位置的null值
增强for循环的局限性
增强for循环只能够对集合中的元素进行取出操作,而无法对集合中的元素进行修改,还有一些简单的操作无法使用高级for循环,例如打印helloworld 100次。例如:String[] arr = {"abc","hhh","jjj"}; for (String s : arr) { s = "N"; // 没有改变数组中的元素 } System.out.println(Arrays.toString(arr)); for (int i = 0; i < arr.length; i++) { arr[i] = "N"; // 数组中的元素被改变 } System.out.println(Arrays.toString(arr));
关于负数的取模运算
以前上C语言的时候老师说负数不能进行取模运算,但是C99中负数可以进行取模运算。Java中对于负数的取模和C99标准一样。System.out.println(7%-3); // 1 System.out.println(-7%-3); // -1 System.out.println(-7%3); // -1 System.out.println(-7%-3); // -1
C99中规定:
不管在什么情况下,如果a和b都是整数,则a mod b = a - (a / b) * b。
相关文章推荐
- Java中的一些奇淫技巧总结
- 移动端bug总结和一些奇淫技巧
- Java中一些关键字的使用技巧总结
- 【Java学习】eclipse,javaWeb项目的一些技巧,经验总结,持续更新
- 总结两个Javascript的哈稀对象的一些编程技巧
- 总结两个Javascript的哈稀对象的一些编程技巧
- 关于这两天的学到的一些java编界面时的一些技巧或方法。
- 关于JAVA垃圾收集器与类的finalize()方法的一些总结
- java技巧总结及tip
- 面试时的一些关键技巧总结
- 再总结一些技巧
- 【转载】JAVA 开发工具Jcreator使用技巧总结
- Java 正则表达式学习总结和一些小例子
- javascript创建页面蒙板的一些知识技巧总结第1/3页
- jdbc编程中的一些常用的技巧[总结]
- 关于java构造器的一些总结
- jdbc编程中的一些常用的技巧[总结]
- JAVA 开发工具Jcreator使用技巧总结 (转)
- 一些英文写作的语言技巧总结
- 一些技巧总结集合对象的查询示例代码 / for each next