COMMON JAVA JAVA数据结构与常用类库简介 Bingoo JAVA类加载 Java Classloading • Why do we care? – Because if we’re gonna write code at runtime, we’d better know how to load and use it… – Because we don’t really understand classes • So… what identifies a class? – Its name – Its package – Its classloader • It means that – We can have multiple instances of a class loaded at the same time – Two instances of the same class from different classloaders are not compatible and not assignable – Static variables are static only in the context of a classloader, not globally as we’re always told Java Classloading • So what is this classloader? – A Java class (subclass of java.lang.ClassLoader), responsible for loading other classes used by the JVM – Classloaders are arranged as a tree • Bootstrap classloader – Loads the Java system • • • • • • • jre/lib/resources.jar – series of resource files jre/lib/rt.jar – the java.*, javax.*, etc packages jre/lib/sunrsasign.jar jre/lib/jsse.jar – secure socket extension jre/lib/jce.jar – Java cryptography extension jre/lib/charsets.jar jre/classes – The important stuff is in rt.jar – the base Java classes Java Classloading Commandline Java App Tomcat (6) Bootstrap classloader Loads only bootstrap.jar and tomcat-juli.jar Ext classloader Loads Tomcat commons library jars Application / System classloader Loads the Application Jars from the classpath Application / System classloader Common classloader Loads jars in the webapp lib directory WAR 1 classloader WAR 2 classloader 自定义类加载器加载一个类的步骤 ClassNotFoundException and NoClassDefFoundError • ClassNotFoundException comes when JVM tries to load a class at runtime dynamically means you give the name of class at runtime and then JVM tries to load it and if that class is not found in classpath it throws ClassNotFoundException • While in case of NoClassDefFoundError the problematic class was present during Compile time and that's why program was successfully compile but not available during runtime by any reason. aopalliance-1.0.jar asm-3.3.jar asm-commons-3.3.jar asm-tree-3.3.jar axis-1.4.jar bcprov-jdk16-1.45.jar cglib-nodep-2.2.jar commons-beanutils-1.8.3.jar commons-codec-1.5.jar commons-collections-3.2.jar commons-discovery-0.4.jar commons-fileupload-1.2.2.jar commons-httpclient-3.1.jar commons-io-2.0.1.jar commons-lang-2.1.jar commons-logging-1.1.1.jar commons-net-2.2.jar commons-pool-1.6.jar commons-ssh-1.5.1.jar dom4j-1.6.1.jar ems-consumer-0.0.1-SNAPSHOT.jar fastjson-1.1.17.jar freemarker-2.3.18.jar guava-12.0.jar hadoop-core-0.20-append-r1056497.jar hbase-0.90.4.jar hessian-3.1.6.jar ibatis-sqlmap-2.3.4.726.M01.jar javassist-3.11.0.GA.jar jline-0.9.94.jar jmockit-0.999.4.jar jsch-0.1.46.jar jsr305-1.3.9.jar junit-4.8.2.jar kafka-0.7.0.jar Linkage-EcsCommon-0.0.1.jar log4j-1.2.16.jar ntfPlat-mailsend-0.0.1.jar spring-context-support-2.5.6.ja ntfplat-send-0.0.1.jar spring-core-2.5.6.jar ognl-3.0.4.jar spring-web-2.5.6.jar PageSecurity-0.0.2.jar spring-webmvc-2.5.6.jar phw-all-0.1.0.jar spymemcached-2.8.0.jar ProxyForEcsSms-1.0.jar struts2-convention-plugin-2.3. scala-library-2.8.0.jar struts2-core-2.3.1.2.jar slf4j-api-1.6.2.jar struts2-json-plugin-2.3.1.2.jar slf4j-log4j12-1.6.2.jar wsdl4j-1.6.2.jar solr-solrj-3.4.0.jar xerces-2.6.2.jar spring-2.5.6.jar xwork-core-2.3.1.2.jar spring-beans-2.5.6.jar zkclient-0.1.jar spring-context-2.5.6.jar zookeeper-3.3.3.jar JAVA Exception 几种设计异常的最佳实践 (Best Practises for Designing the API) • • • • • • 选择Checked还是Unchecked的几个经典依据 Exception的封装问题 如无必要不要创建自己的Exception 不要用Exception来作流程控制 不要轻易的忽略捕获的Exception 不要简单地捕获顶层的Exception 三种”情景”导致异常的抛出 • 编程错误导致(Exception due Programming errors) – 这种情景下,异常往往处于编程错误(如: NullPointerException 或者 IllegalArgumentException),这时异 常一旦抛出,客户端将变得无能为力。 • 客户端代码错误导致(Exception due client code errors) – 客户端试图调用API不允许的操作 • 资源失败导致(Exception due to resource failures) – 如内存不足或网络连接失败导致出现异常等。这些 异常的出现客户端可以采取相应的措施来恢复应用 程序的继续运行。 Java中异常的类型 Checked and Unchecked Exceptions A checked exception is one that will be checked by the compiler for a surrounding try/catch block if that method have a throws clause An unchecked exception, also called a RuntimeException, does not require programmer intervention with a try/catch block Either there is nothing we can do with this type of problem (sun) Or, this type of problem can be remedied by fixing code ○ For example, an ArrayIndexOutOfBounds Checked or Unchecked exception • 问自己一个问题,“如果这种异常一旦抛 出,客户端会做怎样的补救?” – 如果客户端可以通过其他的方法恢复异常,那 么这种异常就是checked exception; – 如果客户端对出现的这种异常无能为力,那么 这种异常就是Unchecked exception; – 尽量使用unchecked exception来处理编程错误; 譬如:NullPointerException , IllegalArgumentException 和 IllegalStateException 保护封装性(Preserve encapsulation) • 不要让你要抛出的checked exception升级到 较高的层次。 – 例如,不要让SQLException延伸到业务层。业务 层并不需要(不关心?)SQLException。 – 转变SQLException为另外一个checked exception, 如果客户端并不需要恢复这种异常的话; – 转变SQLException为一个unchecked exception, 如果客户端对这种异常无能为力的话(多数情 况); 使用异常最佳实践 • 总是要做一些清理工作(Always clean up after yourself) – 如果使用一些资源例如数据库连接或者网络连接,请记住要做一些清理 工作(如关闭数据库连接或者网络连接) – 要用try-finally来做必要的清理工作 • 不要使用异常来控制流程(Never use exceptions for flow control) • 不要忽略异常 – 当有异常被抛出的时候,如果你不想恢复它,那么你要毫不犹豫的将其 转换为unchecked exception,而不是用一个空的catch块或者什么也不做来 忽略它,以至于从表面来看象是什么也没有发生一样。 • 不要捕获顶层的Exception – unchecked exception都是RuntimeException的子类,RuntimeException又继 承Exception,因此,如果单纯的捕获Exception,那么你同样也捕获了 RuntimeException,它将忽略所有的异常,包括unchecked exception. • Log exceptions just once – Logging the same exception stack trace more than once can confuse the programmer examining the stack trace about the original source of exception. So just log it once. Add Java Exception Breakpoint Guava Throwables try { someMethodThatCouldThrowAnything(); } catch (IKnowWhatToDoWithThisException e) { handle(e); } catch (Throwable t) { Throwables.propagateIfInstanceOf(t, IOException.class); Throwables.propagateIfInstanceOf(t, SQLException.class); throw Throwables.propagate(t); } @Annotations Annotation Definition Structured Data Comparable to records in OCaml @interface MyAnnotation { String value(); // member int i() default 123; // member w. default value } @interface MarkerAnnotation { // annotation without any members } Annotation Usage @MyAnnotation(value="text", i=456) void method() { … } // default value for i: 123 @MyAnnotation(value="text") void method2() { … } // special case for members called "value" @MyAnnotation("text") void method3() { … } // parenthesis can be omitted if no members @MarkerAnnotation void method4() { … } Annotation Members @interface MyAnnotation { int String Class SomeEnum intMember(); stringMember(); classMember(); enumMember(); // // // // primitives strings class literals enums // annotions OnlyThreadWithName annotMember(); // arrays of the above OnlyThreadWithName[] arrayMember(); } Annotation Targets in Java 5 @A package some.package.name; @B class MyClass { @C Object field; @D MyClass(@E Object param) { field = param; } @F Object method() { @G Object localVar = field; return localVar; } } The Target annotation @Target(ElementType.TYPE) —can be applied to any element of a class @Target(ElementType.FIELD) —can be applied to a field or property @Target(ElementType.METHOD) —can be applied to a method level annotation @Target(ElementType.PARAMETER) —can be applied to the parameters of a method @Target(ElementType.CONSTRUCTOR) —can be applied to constructors @Target(ElementType.LOCAL_VARIABLE) —can be applied to local variables @Target(ElementType.ANNOTATION_TYPE) —indicates that the declared type itself is an 告知程序如何处理@Retention java.lang.reflect.AnnotatedElement接口 public Annotation getAnnotation(Class annotationType); public Annotation[] getAnnotations(); public Annotation[] getDeclaredAnnotations(); public boolean isAnnotationPresent(Class annotationType); Class、Constructor、Field、Method、Package等类别,都实现了 AnnotatedElement接口 Java Logging Logging use-cases • • • • • debugging the software during development help diagnose bugs during production trace access for security purposes create data for statistical use etc History • System.out.println() • System.err.println() • e.printStackTrace() Components Level/ Priority Aplicaction Logger 1..* Filter Appender Layout Logger Named Hierarchy A logger is said to be an ancestor of another logger if its name followed by a dot is the prefix part in the descendant logger name. PS: 大小写敏感 root com.site.software com.site.software.model com.site.software.model.dao com.site.software.model.dao.PersonDAOImpl com.site.software.view com.site.software is an ancestor logger of the descendant com.site.software.model.dao ●com.site.software is the parent logger of the child com.site.software.model ● Levels A logger may be assigned to a level. ● ● ● ● Properties configuration file log4j.rootLogger=ERROR log4j.logger.com.site.software=INFO XML configuration file Java configuration file Logger.getRootLogger().setLevel(Level.ERROR); Logger.getLogger(“com.site.software”).setLevel(Level.INFO); levels are ordered TRACE < DEBUG < INFO < WARN < ERROR < FATAL Level/ Priority • FATAL: Displays messages of situations that probably will abort the application. • ERROR: Displays error messages that are unwanted but not interrupt the application. • WARN: Displays messages from dangerous regions for the application, or certain operations use not recommended. • INFO: Displays information messages about the execution of the application, or important events. • DEBUG: Shows debug messages for the application. (Used in development time) • ALL: Show all posts • OFF: Disables all messages. Level Inheritance The inherited level for a given logger L, is equal to the first non-null level in the logger named hierarchy, starting at L and proceeding upwards in the hierarchy towards the root logger. Logger Name root com.site.software com.site.software.model com.site.software.model.dao com.site.software.model.dao.PersonDAOImpl com.site.software.view Assigned Inherited Level level ERROR WARN INFO null null null ERROR WARN INFO INFO INFO WARN Level继承1 Logger name Assigned level Effective level root DEBUG DEBUG X none DEBUG X.Y none DEBUG X.Y.Z none DEBUG Logger name Assigned level Effective level root ERROR ERROR X INFO INFO X.Y DEBUG DEBUG X.Y.Z WARN WARN Level继承2 Logger name Assigned level Effective level root DEBUG DEBUG X INFO INFO X.Y none INFO X.Y.Z ERROR ERROR Logger name Assigned level Effective level root DEBUG DEBUG X INFO INFO X.Y none INFO X.Y.Z none INFO Logging Request A log request of level p in a logger configured (either assigned or inherited, whichever is appropriate) with level q, is enabled if p >= q. import org.apache.log4j.Logger; public class PersonDAOImpl { private final Logger LOG = Logger.getLogger(PersonDAOImpl.class); public PersonDAOImpl() { LOG.debug("You can't see me in the log because debug < INFO"); LOG.info("You will see me in the log because info = INFO"); LOG.warn("You will see me in the log because warn > INFO"); Appenders A logger may be assigned to an appender: a named output destination your log messages are forwarded to. # The root logger logs to the console log4j.rootLogger=ERROR, con # The com.site.software logger logs to a file log4j.logger.com.site.software=INFO, FileApp # The con appender will log in the console log4j.appender.con=org.apache.log4j.ConsoleAppender #The FileApp appender will log in a file log4j.appender.FileApp=org.apache.log4j.FileAppender Appenders Appender Additivity Each enabled logging request for a given logger L will be forwarded to all the appenders in that logger LA as well as all the appenders higher HA in the logger named hierarchy . Logger Name root com.site.software com.site.software.model com.site.software.model.dao com.site.software.view LA con null FileApp, c d e HA con con FileApp, c, con con Additivity Flag Logger Name Attached Appenders Additivi Output Targets ty Flag Comment root A1 not applica A1 ble Since the root logger stands at the top of the logger hierarchy, the additivity flag does not apply to it. x x.y A-x1, A-x2 true none true A1, A-x1, A-x2 A1, A-x1, A-x2 x.y.z A-xyz1 A1, A-x1, A-x2, A-xyz1 Appenders of "x.y.z", "x" and of root. A-sec No appender accumulation since the additivity flag is set to false. Only appender A-sec will be used. A-sec Only appenders of "security" because the additivity flag in "security" is set to false. security A-sec security. none access true false true Appenders of "x" and of root. Appenders of "x" and of root. Layout Conversion Pattern Each appender has a layout component responsible for formatting log messages accordingly to conversion patterns. log4j.appender.con=org.apache.log4j.ConsoleAppender log4j.appender.con.layout=org.apache.log4j.PatternLayout log4j.appender.con.layout.ConversionPattern=%d [%t] %-5p %m (%c:%L)% Produced logs: 2010-05-14 19:29:11,996 [main] INFO You will see me in the log because info = INFO (com.site.software.model.dao.PersonDAOImpl:10) 2010-05-14 19:29:11,997 [main] WARNYou will see me in the log because warn > INFO (com.site.software.model.dao.PersonDAOImpl:11) A lot of Appenders and Layouts Appenders ● ConsoleAppender appends log events to System.out or System.err ● FileAppender appends log events to a file ● RollingFileAppender extends FileAppender to backup the log files when they reach a certain size ● DailyRollingFileAppender extends FileAppender so that the underlying is rolled over at a user chosen frequency ● SMTPAppender sends an e-mail when a specific logging event occurs ● JMSAppender publishes log events to a JMS Topic ● JDBCAppender provides for sending log events to a database Layouts ● PatternLayout configurable string pattern in a printf C function style ● XMLLayout appends log events as a series of log4j:event (log4j.dtd) ● HTMLLayout outputs events in a HTML table The API 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Wombat { private final Logger logger = LoggerFactory.getLogger(Wombat.class); Integer t; Integer oldT; public void setTemperature(Integer temperature) { oldT = t; t = temperature; logger.debug("Temperature set to {}. Old temperature was {}.", t, oldT); if(temperature.intValue() > 50) { logger.info("Temperature has risen above 50 degrees."); } } } SLF4J & Logback logback的前世今生 • • slf4j由log4j作者Ceki开发,逐步取代apahce commons logging。 logback由log4j作者Ceki开发,逐步取代 log4j。 logback相比较log4j的优势 • slf4j支持参数化 – – • logger.error(“帐号ID:{}不存在”, userId); 告别了if(logger.isDebugEnable()) 时代 另外logback的整体性能比log4j也较佳, hibernate等项目已经采用了slf4j。 SLF4J and Logback : Dream Dates! • • • • Logback implements SLF4J natively No computational and memory overhead Fully compliant to SLF4J Faster they say! 10 times!! Smaller Blue Print • Core, classic and access modules Why Logback • Conditional Processing – Good For Dev/Prod switch Is It Worth A Use? Why Logback Stack Traces Pointing jar files logback.xml ConsoleAppender RollingFileAppender rollover daily or whenever the file size reaches 100MB Parameterized logging inefficient syle logger.debug("Hello "+name); old style: if(logger.isDebugEnabled()) { logger.debug("Hello "+name); } new style: logger.debug("Hello {}", name); SiftingAppender or the appender-making appender • Sift logging according to runtime attributes • E.g. separate logs according to user sessions, so that the log file generated by every user go into distinct log files, one log file per user. • Works with any appender, not just FileAppender SiftingAppender (continued) <appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender"> <discriminator> <Key>userid</Key> <DefaultValue>unknown</DefaultValue> </discriminator> <sift> <appender name="FILE-${userid}" class="ch.qos.logback.core.FileAppender"> <File>${userid}.log</File>s <Append>false</Append> <layout> <Pattern>%d %level %mdc %logger - %msg%n</Pattern> </layout> </appender> </sift> </appender> Mapped Diagnostic Context(MDC) • 线程映射表 • 日志框架维护的 map,日志框架通过提供 了的键值对向其中插入日志信息。 映射诊断环境(Mapped Diagnostic Context) Logback的设计目标之一是审查和调试复杂的分布式应用程序。真实世界的多 数分布式系统需要同时处理多个客户端。在一个典型的多线程方式实现的分 布式系统里,不同的线程处理不同的客户端。区分不同客户端的记录输出的 一个可行的但不好的方法是为每个客户端都创建新的、独立的logger。这种 技术使logger的数量增多且大大增加了管理开销。 一个轻量的技术是为客户端的每个记录请求添加唯一戳(uniquely stamp) Logback在SLJ4J里使用了这种技术的一种变体:映射诊断环境(MDC) 为了给每个请求添加唯一戳,用户把环境(context)信息放进MDContext) MDC • MDC : Map Diagnostic Context – Helps to uniquely stamp requests – Similar to NDC : Nested Diagnostic Context – Correlating the logs effectively • The MDC manages contextual information on a per thread basis(and its children) @Override public void processMsg(EmsMessage emsMessage) { EopLogBean msg = (EopLogBean) emsMessage.getMsg(); MDC.put(“userid", getActionFromTxid(msg.getTrxid())); log.info(msg.toString()); } MDC Use Case: User Based Logging public class UserServletFilter implements Filter { private final String USER_KEY = "username"; public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; Principal principal = req.getUserPrincipal(); if (principal != null) { String username = principal.getName(); MDC.put(USER_KEY, username); } try { chain.doFilter(request, response); } finally { MDC.remove(USER_KEY); } } } MDC Use Case: User Based Logging <appender name="CONSOLE“ class="ch.qos.logback.core.ConsoleAppender"> <layout class="ch.qos.logback.classic.PatternLayout"> <Pattern>%-4r [%thread] %-5level C:%X{username} - %msg%n</Pattern> </layout> </appender> MDC Use Case: InsertingServletFilter • %X{req.remoteHost} • %X{req.requestURI}%n%d - %m%n Package versions in stack traces java.lang.NullPointerException at com.xyz.Wombat(Wombat.java:57) ~[wombat-1.3.jar:1.3] at com.xyz.Wombat(Wombat.java:76) ~[wombat-1.3.jar:1.3] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native) ~[na:1.5.0_06] at java.lang.reflect.Method.invoke(Method.java:585) ~[na:1.5.0_06] at junit.runners.TestMethod.invoke(TestMethod.java:59) [junit-4.4.jar:na] etc.. 60 JAVA String String StringUtils 空白: defaultIfBlank defaultIfEmpty defaultString deleteWhitespace normalizeSpace trim 判断: isAllLowerCase isAlpha isAlphanumeric isAlphanumericSpace isAlphaSpace isAsciiPrintable isNumeric isNumericSpace isWhitespace isBlank isEmpty isNotBlank isNotEmpty 合分: join split 结束: endsWith endsWithAny endsWithIgnoreCase 比较: difference equals equalsIgnoreCase getCommonPrefix getLevenshteinDistance overlay 查找: indexOf indexOfAny indexOfAnyBut indexOfDifference indexOfIgnoreCase lastIndexOf lastIndexOfAny lastIndexOfIgnoreCase lastOrdinalIndexOf ordinalIndexOf 删除: remove removeEnd removeEndIgnoreCase removeStart removeStartIgnoreCase 替换: replace replaceChars replaceEach replaceEachRepeatedly replaceOnce 反转: reverse reverseDelimited 子串: countMatches left mid right substring… 补充: leftPad repeat rightPad 大小写: capitalize lowerCase uncapitalize upperCase swapCase 缩略: abbreviate abbreviateMiddle 补充: center 裁剪: chomp chop strip… 包含:contains containsAny containsIgnoreCase containsNone containsOnly containsWhitespac GuavaSplitter JDK has splitter ‣ regular expression ‣ result as an array ‣ its way of handling empty pieces Mini-puzzler ",a,,b,".split(",") returns... (a) "","a","","b","" (b) null,"a",null,"b",null (c) "a",null,"b" (d) "a","b" (e) None of the above (which is very strange) Splitter Breaks strings into substrings by recognizing a separator (delimiter), one of: a single character: Splitter.on('\n') a literal string: Splitter.on(", ") a regex: Splitter.onPattern(",\\s*") any CharMatcher (remember that?) or using a fixed substring length Splitter.fixedLength(8) Iterable<String> pieces = Splitter.on(',').split("trivial,example") returns "trivial" and "example" in order. The default behavior is simplistic: //yields [" foo", " ", "bar", " quux", ""] Splitter.on(',').split(" foo, ,bar, quux,"); If you want extra features, ask for them! //yields ["foo", "bar", "quux"] Splitter.on(',') .trimResults() .omitEmptyStrings() .split(" foo, ,bar, quux,"); Guava Joiner Bizarrely Missing From The JDK Class Libraries: joining pieces of text with a separator. String s = Joiner.on(", ").join(episodesOnDisc); Joiner is configurable: StringBuilder sb = ...; Joiner.on("|").skipNulls().appendTo(sb, attrs); It can even handle maps: static final MapJoiner MAP_JOINER = Joiner.on("; ") .useForNull("NODATA") .withKeyValueSeparator(":"); String到基本数据类型的转换 • public static int parseInt(String s, int radix) throws NumberFormatException • public static int parseInt(String s) • public static byte parseByte(String s) • public static short parseShort(String s) • public static long parseLong(String s) • public static float parseFloat(String s) • public static double parseDouble(String s) 对象的字符串表示方法 • Object类 public String toString() • String类 – – – – – public static String valueOf(char c) public static String valueOf(int i) public static String valueOf(long l) public static String valueOf(float f) public static String valueOf(double d) BASE64 01 02 03 04 05 06 07 08 09 10 11 12 import static javax.xml.bind.DatatypeConverter.parseBase64Binary; import static javax.xml.bind.DatatypeConverter.printBase64Binary; @Test public void testBase64() { String s1 = "我是黄进兵!"; String base64 = printBase64Binary(s1.getBytes(UTF_8)); assertEquals("5oiR5piv6buE6L+b5YW1IQ==", base64); byte[] bytes = parseBase64Binary(base64); String s2 = new String(bytes, UTF_8); assertEquals(s1, s2); } JAVA IO Java Characters • A Java character has two bytes • Java supports Unicode character set standard – ASCII • Java uses UTF-16 encoding • Other unicode encodings: – UTF-8 – UTF-16 • Other non-unicode encodings – Windows-1256 Stream Concept Java I/O Classes • Text I/O – Stream of characters (Unicode format) – Support provided by Reader and Writer • Binary I/O – Stream of bytes (raw format) – Support provided by InputStream and OutputStream – An InputStream reads raw octet (8 bit) data (byte). Reader和InputStream区别 • Reader和InputStream分别是I/O库提供的两套平行独立的等级机构 • InputStream、OutputStream是用来处理8位元的流,Reader、Writer是 用来处理16位元的流。 • InputStream、OutputStream是用来处理8位元的流,Reader、Writer是 用来处理16位元的流。所以在处理中文的时候需要用Reader和Writer。 • InputStreamReader、OutputStreamWriter负责进行InputStream到 Reader的适配和由OutputStream到Writer的适配。 • int copy(InputStream input, OutputStream output) • void copy(InputStream input, Writer output, String encoding) • void copy(Reader input, OutputStream output, String encoding) • int copy(Reader input, Writer output) Reader <-> InputStream Writer <->WriterOutputStream • • • • • • Reader->InputStream commons-io :ReaderInputStream Writer->OutputStream commons-io :WriterOutputStream InputStream->Reader jdk:InputStreamReader OutputStream->Writer jdk:OutputStreamWriter InputStream->OutputStream? Reader->Writer? Closeable • • • • Reader何时关闭? Writer何时关闭? InputStream 何时关闭? OutputStream何时关闭? FileUtils Guava common.io Typically: InputSupplier<InputStream>, OutputSupplier<Writer>,etc. 2 key interfaces public interface InputSupplier<T> { T getInput() throws IOException; } public interface OutputSupplier<T> { T getOutput() throws IOException; } This lets all Guava’s utilities be useful for many kinds of I/O. Terminology ‣ byte stream means "InputStream or OutputStream" ByteStreams utilities class ‣ char stream means "Reader orWriter." CharStreams utilities class common.io: ByteStreams byte[] toByteArray(InputStream) byte[] toByteArray(InputSupplier) void readFully(InputStream, byte[]) void write(byte[], OutputSupplier) long copy(InputStream, OutputStream) long copy(InputSupplier, OutputSupplier) long length(InputSupplier) boolean equal(InputSupplier, InputSupplier) InputSupplier slice(InputSupplier, long, long) InputSupplier join(InputSupplier...) CharStreams is similar, but deals in Reader, Writer, String and CharSequence (often requiring you to specify a Charset). common.io: Files The Files class works one level higher than ByteStreams and CharStreams, and has a few other tricks. byte[] toByteArray(File) String toString(File, Charset) void write(byte[], File) void write(CharSequence, File, Charset) long copy(File, File) long copy(InputSupplier, File) long copy(File, OutputSupplier) long copy(File, Charset, Appendable) long move(File, File) boolean equal(File, File) List<String> readLines(File, Charset) More about Files File createTempDir() void deleteDirectoryContents(File) void deleteRecursively(File) long getChecksum(File,Checksum) byte[] getDigest(File,MessageDigest) String readFirstLine(File,Charset) List<String> readLines(File,Charset) T readLines(File,Charset, LineProcessor<T>) String toString(File,Charset) Flushables and Closeablesb Flushables.flushQuietly(Flushable flushable) Flushables.flush( Flushable flushable, boolean swallowIOException) throws IOException Closeables.closeQuietly(Closeable closeable) Closeables.close( Closeable closeable, boolean swallowIOException) throws IOException Very usefull in finally blocks (avoid nesting try/catch) Java Collections Java array and collections JAVA Collections Java Collection Interfaces 4种基本形式,前三种的父接口是Collection。 1:List 关注对象的索引列表 2:Set 关注对象的唯一性 3:Queue 关注对象被处理时的顺序 4:Map 关注映射和键值的唯一性 Collection Utilities List具体实现类 Map具体实现类 Set具体实现类 Queue具体实现类 Multiset Multimap ListMultimap & SetMultimap Map<String, List<T>> & Map<String, Set<T>> Operations: put(K, V), putAll(K, Iterable<V>), remove(K, V), removeAll(K, Iterable<V>), replaceValues(K, Iterable<V>) Multimap Implementations BiMap BiMap<K, V> is Map<K,V> with unique values Operations: all Map, inverse(), values() as Set Throws an IllegalArgumentException if you attempt to map a key to an already-present value BiMap Implementations Table Copy! Lists.newArrayList() Lists.newLinkedList() Sets.newHashSet() Sets.newLinkedHashSet() Sets.newTreeSet() or make it immutable.. ImmutableList.copyOf() ImmutableSet.copyOf() 不同集合类型有不同的时间复杂度 Operation Obtain size Add element Remove given element Remove by index Get element by index Find out if contains ArrayList LinkedList HashSet TreeSet Constant Constant Linear Linear Constant Linear Constant Constant Linear Linear Linear Linear Constant Constant Constant – – Constant Constant Log Log – – Log Depending on the size, different types of collections may behave better that others how to choose correct java collection class (When to use which collection in java ) 泛型练习 • 泛型改造MyStack • 增加方法: pushAll • 增加方法: popAll @Test public void testStack() { MyStack<Number> numberStack = new MyStack<Number>(); Collection<Integer> integers = new ArrayList<Integer>(); integers.add(1); numberStack.pushAll(integers); Collection<Object> objects = new ArrayList<Object>(); numberStack.popAll(objects); } The Get and Put Principle public static <T> void copy(List<? super T> dest, List<? extends T> src) use an extends wildcard when you only get values out of a structure, use a super wildcard when you only put values into a structure, and don't use a wildcard when you both get and put. A Mnemonic for Wildcard Usage • PECS—Producer extends, Consumer super – use Foo<? extends T> for a T producer – use Foo<? super T> for a T consumer • Only applies to input parameters – Don’t use wildcard types as return types Misc. • Tuples • The of-Operator • ULong, UInt, UShort Java Reflections Metadata Java stores metadata in classes - - Metadata for a class: Metadata for a constructor: Metadata for a field: Metadata for a method: java.lang.Class java.lang.reflect.Constructor java.lang.reflect.Field java.lang.reflect.Method Two ways to access a Class object for a class: Class c1 = Class.forName(“java.util.Properties”); Object obj = ...; Class c2 = obj.getClass(); Reflection classes are inter-dependent - Examples are shown on the next slide Examples of inter-relatedness of reflection classes class Class { Constructor[] Field Field[] Method[] ... getConstructors(); getDeclaredField(String name); getDeclaredFields(); getDeclaredMethods(); } class Field { Class getType(); ... } class Method { Class[] getParameterTypes(); Class getReturnType(); ... } Metadata for primitive types and arrays Java associates a Class instance with each primitive type: Class c1 = int.class; Class c2 = boolean.class; Class c3 = void.class; Might be returned by Method.getReturnType() Use Class.forName() to access the Class object for an array Class Class Class Class c4 c5 c6 c7 = = = = byte.class; // byte Class.forName(“[B”); // byte[] Class.forName(“[[B”); // byte[][] Class.forName(“[Ljava.util.Properties”); Encoding scheme used by Class.forName() B byte; C char; D double; F float; I int; J long; Lclass-name class-name[]; S short; Z boolean Use as many “[”s as there are dimensions in the array Miscellaneous Class methods Here are some useful methods defined in Class class Class { public String getName(); // fully-qualified name public boolean isArray(); public boolean isInterface(); public boolean isPrimitive(); public Class getComponentType(); // only for arrays ... } Invoking a default constructor Use Class.newInstance() to call the default constructor Example: abstract class Foo { public static Foo create() throws Exception { String className = System.getProperty( “foo.implementation.class”, “com.example.myproject.FooImpl”); Class c = Class.forName(className); return (Foo)c.newInstance(); } abstract void op1(...); abstract void op2(...); } ... Foo obj = Foo.create(); obj.op1(...); A plug-in architecture Use a properties file to store a mapping for plugin name class name Many tools support plugins: Ant, Maven, Eclipse, … abstract class Plugin { abstract void op1(...); abstract void op1(...); } abstract class PluginManager { public static Plugin load(String name) throws Exception { String className = props.getProperty(name); Class c = Class.forName(className); return (Plugin)c.newInstance(); } } ... Plugin obj = PluginManager.load(“...”); Invoking a non-default constructor Slightly more complex than invoking the default constructor: -Use Class.getConstructor(Class[] parameterTypes) -Then call Constructor.newInstance(Object[] parameters) abstract class PluginManager { public static Plugin load(String name) throws Exception { String className = props.getProperty(name); Class c = Class.forName(className); Constructor cons = c.getConstructor( new Class[]{String.class, String.class}); return (Plugin)cons.newInstance( new Object[]{“x”, “y”}); } } ... Plugin obj = PluginManager.load(“...”); Passing primitive types as parameters If you want to pass a primitive type as a parameter: Wrap the primitive value in an object wrapper Then use the object wrapper as the parameter Object wrappers for primitive types: - boolean byte char int ... java.lang.Boolean java.lang.Byte java.lang.Character java.lang.Integer Invoking a method Broadly similar to invoking a non-default constructor: Use Class.getMethod(String name, Class[]parameterTypes) Then call Method.invoke(Object target, Object[] parameters) Object obj = ... Class c = obj.getClass(); Method m = c.getMethod(“doWork”, new Class[]{String.class, String.class}); Object result= m.invoke(obj, new Object[]{“x”,“y”}); Looking up methods The API for looking up methods is fragmented: - You can lookup a public method in a class or its ancestor classes Or, lookup a public or non-public method declared in the specified class A better name would have been getPublicMethod() class Class { public Method getMethod(String name, Class[] parameterTypes); public Method[] getMethods(); public Method getDeclaredMethod(String name, Class[] parameterTypes); public Method[] getDeclaredMethods(); ... } Finding an inherited method This code searches up a class hierarchy for a method -Works for both public and non-public methods Method findMethod(Class cls, String methodName, Class[] paramTypes) { Method method = null; while (cls != null) { try { method = cls.getDeclaredMethod(methodName, paramTypes); break; } catch (NoSuchMethodException ex) { cls = cls.getSuperclass(); } } return method; } Accessing a field There are two ways to access a field: - By invoking get- and set-style methods (if the class defines them) By using the code shown below Object obj = ... Class c = obj.getClass(); Field f = c.getField(“firstName”); f.set(obj, “John”); Object value = f.get(obj); Looking up fields The API for looking up fields is fragmented: - You can lookup a public field in a class or its ancestor classes Or, lookup a public or non-public field declared in the specified class A better name would wouldhave havebeen been getPublicField() getPublicField() class Class { public Field public Field[] public Field public Field[] ... } getField(String name); getFields(); getDeclaredField(String name); getDeclaredFields(); Finding an inherited field This code searches up a class hierarchy for a field - Works for both public and non-public fields Field findField(Class cls, String fieldName) { Field field = null; while (cls != null) { try { field = cls.getDeclaredField(fieldName); break; } catch (NoSuchFieldException ex) { cls = cls.getSuperclass(); } } return field; } Java modifiers Java defines 11 modifiers: - Some of the modifiers can be applied to a class, method or field: - abstract, final, native, private, protected, public, static, strictfp, synchronized, transient and volatile Set of modifiers is represented as bit-fields in an integer Access set of modifiers by calling int getModifiers() Useful static methods on java.lang.reflect.Modifier: static static static static ... boolean boolean boolean boolean isAbstract(int modifier); isFinal(int modifier); isNative(int modifier); isPrivate(int modifier); Accessing non-public fields and methods Both Field and Method define the following methods (inherited from java.lang.reflect.AccessibleObject): boolean isAccessible(); void setAccessible(boolean flag); static void setAccessible(AccessibleObject[] array, boolean flag); Better terminology might have been “SuppressSecurityChecks” instead of “Accessible” Example of use: if (!Modifier.isPublic(field.getModifiers()) { field.setAccessible(true); Hibernate uses this technique so it can serialize non-public JOOR A fluent reflection API for Java jOOR stands for Java Object Oriented Reflection. It is a simple wrapper for the java.lang.reflect package. String world = on("java.lang.String") // Like Class.forName() .create("Hello World") // Call the most specific matching constructor .call("substring", 6) // Call the most specific matching substring() method .call("toString") // Call toString() .get(); // Get the wrapped object, in this case a String Performance // Method reflection with ReflectASM: SomeClass someObject = ... MethodAccess access = MethodAccess.get(SomeClass.class); access.invoke(someObject, "setName", "Awesome McLovin"); String name = (String)access.invoke(someObject, "getName"); Comparison with standard java.lang.reflect Employee[] employees = on(department).call("getEmployees").get(); jOOR code: for (Employee employee : employees) { Street street = on(employee).call("getAddress").call("getStreet").get(); System.out.println(street); } try { Method m1 = department.getClass().getMethod("getEmployees"); Employee employees = (Employee[]) m1.invoke(department); The same example with normal reflection in Java: for (Employee employee : employees) { Method m2 = employee.getClass().getMethod("getAddress"); Address address = (Address) m2.invoke(employee); Method m3 = address.getClass().getMethod("getStreet"); Street street = (Street) m3.invoke(address); System.out.println(street); } } // There are many checked exceptions that you are likely to ignore anyway catch (Exception ignore) { // ... or maybe just wrap in your preferred runtime exception: throw new RuntimeException(e); } JavaScript Object Notation Eclipse json editor { hotelList:[ {name:"Beijing",address:"Haidian Road {name:"Beijing",address:"Haidian Road {name:"Beijing",address:"Haidian Road {name:"Beijing",address:"Haidian Road {name:"Beijing",address:"Haidian Road {name:"Beijing",address:"Haidian Road {name:"Beijing",address:"Haidian Road ], timeStamp:"Wed Oct 08 10:25:10 CST 2008" } NO:1",price:110.0}, NO:2",price:120.0}, NO:3",price:130.0}, NO:4",price:140.0}, NO:5",price:150.0}, NO:6",price:160.0}, NO:7",price:170.0} JSON Form View What is JSON? • Lightweight data-interchange format > Compared to XML • Simple format > Easy for humans to read and write > Easy for machines to parse and generate • JSON is a text format > Programming language independent > Uses conventions that are familiar to programmers of the C- family of languages, including C, C++, C#, Java, JavaScript, Perl, Python Why Use JSON over XML • Lighter and faster than XML as on-the-wire data format • JSON objects are typed while XML data is typeless > JSON types: string, number, array, boolean, > XML data are all string • Native data form for JavaScript code > Data is readily accessible as JSON objects in your JavaScript code vs. XML data needed to be parsed and assigned to variables through tedious DOM APIs > Retrieving values is as easy as reading from an object property in your JavaScript code JSON Tools for Java Developer • Parser > Parse JSON text files and convert these to a Java model • Renderer > Render a Java representation into text • Serializer > Serialize plain POJO clusters to a JSON representation • Validator > Validate the contents of a JSON file using a JSON schema Alibaba FastJSON 基本序列化 Object o = ...; String text = JSON.toJSONString(o); 反序列化 String text = ...; // {"r":255,"g":0,"b":0,"alpha":255} Color color = JSON.parseObject(text, Color.class); JSON Schema { "$schema" : "http://json-schema.org/draft-03/schema#", "id" : "http://json-schema.org/draft-03/schema#", "type" : "object", "properties" : { "type" : { "type" : ["string", "array"], "items" : { "type" : ["string", {"$ref" : "#"}] }, "uniqueItems" : true, "default" : "any" }, "properties" : { "type" : "object", "additionalProperties" : {"$ref" : "#"}, "default" : {} }, XML tools http://code.google.com/p/xmltool/ XMLTag tag = XMLDoc.newDocument(false) .addDefaultNamespace("http://www.w3.org/2002/06/xhtml2/") .addNamespace("wicket", "http://wicket.sourceforge.net/wicket-1.0") .addRoot("html") .addTag("wicket:border") .gotoRoot().addTag("head") .addNamespace("other", "http://other-ns.com") .gotoRoot().addTag("other:foo"); System.out.println(tag.toString()); XML tools Features • Create new XML documents from external sources or new document from scrash • Manage namespaces • Manipulating nodes (add, remove, rename) • Manipulating data (add, remove text or CDATA) • Navigate into the document with shortcuts and XPath (note: XPath supports namespaces) • Tranform an XMlDoc instance to a String or a Document • Validate your document against schemas • Executin callbacks on a hierarchy • Remove all namspaces (namespace ignoring) • ... and a lot of other features ! jOOX-Java Object Oriented XML // Find the order at index for and add an element "paid" $(document).find("orders").children().eq(4).append("<paid>true</paid>"); // Find those orders that are paid and flag them as "settled" $(document).find("orders").children().find("paid").after("<settled>true</s ettled>"); // Add a complex element $(document).find("orders").append( $("order", $("date", "2011-08-14"), $("amount", "155"), $("paid", "false"), $("settled", "false")).attr("id", "13"); JOOQ SELECT * FROM BOOK create.selectFrom(BOOK) WHERE PUBLISHED_IN = 201 .where(PUBLISHED_IN.equal(2011)) 1 .orderBy(TITLE) ORDER BY TITLE SELECT FIRST_NAME, LAST_NAME, COU NT(*) FROM AUTHOR JOIN BOOK ON AUTHOR.ID = BOOK.AUTH OR_ID WHERE LANGUAGE = 'DE' AND PUBLISHED > '2008-01-01' GROUP BY FIRST_NAME, LAST_NAME HAVING COUNT(*) > 5 ORDER BY LAST_NAME ASC NULLS FIRS T LIMIT 2 OFFSET 1 FOR UPDATE OF FIRST_NAME, LAST_NAME create.select(FIRST_NAME, LAST_NAME, count()) .from(AUTHOR) .join(BOOK) .on(Author.ID.equal(Book.AUTHOR_ID)) .where(LANGUAGE.equal("DE")) .and(PUBLISHED.greaterThan(parseDate("2008-01-01"))) .groupBy(FIRST_NAME, LAST_NAME) .having(count().greaterThan(5)) .orderBy(LAST_NAME.asc() .nullsFirst()) .limit(2).offset(1) .forUpdate() .of(FIRST_NAME, LAST_NAME) JOOQ + H2 01 import org.jooq.util.h2.H2Factory; 02 import cn.bingoo.h2.domain.Tables; 03 import cn.bingoo.h2.domain.tables.records.VouchercardRecord; 04 05 @Test 06 public void testJooq() throws Exception { 07 DriverManager.registerDriver(new org.h2.Driver()); 08 Connection conn = DriverManager.getConnection("jdbc:h2:~/bingoo-handy", "sa", ""); 09 Factory factory = new H2Factory(conn); 10 11 VouchercardRecord newRecord = factory.newRecord(Tables.VOUCHERCARD); 12 newRecord.setCode("mycode"); newRecord.setPass("mypass"); newRecord.setHmac("mymac"); 13 newRecord.store(); 14 15 VouchercardRecord fetchOne = factory.selectFrom(Tables.VOUCHERCARD) 16 .where(Tables.VOUCHERCARD.CODE.equal("mycode")).fetchOne(); 17 18 assertEquals(newRecord, fetchOne); 19 20 conn.close(); 21 } Regular Expression正则表达式 • 文本处理的利器(grep, perl, ruby, lua内嵌) • Perl,ruby,javascript 写法 /[a-z]+/ – Eg. name = “Dave”; name =~ /[a-z]/; 找到ave • JDK1.4 java.util.regex • 一些简单例子: [a-z]+ abc [abc] [^abc] 匹配一个或多个小写字母 exactly this sequence of three letters any one of the letters a, b, or c any character except one of the letters a, b, or c (immediately within an open bracket, ^ means “not,” but anywhere else it just means the character ^) [a-z] [a-zA-Z0-9] abc|xyz [A-Za-z]+[0-9] any one character from a through z, inclusive any one letter or digit match either abc or xyz match one or more letters immediately followed by one digit REGEX Regular Expressions Anchors(锚定符) ^ Start of string, or start of line in multi-line pattern \A Start of string $ End of string, or end of line in multiline pattern \Z End of string \b Word boundary \B Not word boundary \< Start of word \> End of word Quantifiers(限定符) X* 0 or more X+ 1 or more X? 0 or 1 X{3} Exactly 3 X{3,} 3 or more X{3,5} 3, 4 or 5 Add a ? to a quantifier to make it ungreedy. Groups and Ranges(分组和范围) . Any character except new line (\n) (a|b) a or b (...) Group (?:...) Passive (non-capturing) group [abc] Range (a or b or c) [^abc] Not a or b or c [a-q] Letter from a to q [A-Q] Upper case letter from A to Q [0-7] Digit from 0 to 7 \n nth group/subpattern Ranges are inclusive. Character Classes(字符分类) \c \s \S \d \D \w \W \x \O Control character 控制字符 White space 空白字符 Not white space 非空白 Digit 数字 Not digit 非数字 Word 单词 Not word 非单词 Hexadecimal digit 16进制 Octal digit 8进制 限定符类型Types of quantifiers • A greedy quantifier will match as much as it can, and back off if it needs to – We’ll do examples in a moment • A reluctant quantifier will match as little as possible, then take more if it needs to – You make a quantifier reluctant by appending a ?: X?? X*? X+? X{n}? X{n,}? X{n,m}? • A possessive quantifier will match as much as it can, and never let go – You make a quantifier possessive by appending a +: X?+ X*+ X++ X{n}+ X{n,}+ X{n,m}+ 限定符示例 • Suppose your text is aardvark – Using the pattern a*ardvark (a* is greedy): • The a* will first match aa, but then ardvark won’t match • The a* then “backs off” and matches only a single a, allowing the rest of the pattern (ardvark) to succeed – Using the pattern a*?ardvark (a*? is reluctant): • The a*? will first match zero characters (the null string), but then ardvark won’t match • The a*? then extends and matches the first a, allowing the rest of the pattern (ardvark) to succeed – Using the pattern a*+ardvark (a*+ is possessive): • The a*+ will match the aa, and will not back off, so ardvark never matches and the pattern match fails JAVA中的Regex 01 import java.util.regex.Matcher; 02 import java.util.regex.Pattern; 03 04 @Test 05 public void testRegex() { 06 Pattern p = Pattern.compile(“[a-z]+”); 07 String text = “Hello world”; 08 Matcher m = p.matcher(text); 09 assertTrue(m.find()); 10 assertEquals("ello", text.substring(m.start(), m.end())); 11 assertTrue(m.find()); 12 assertEquals("world", text.substring(m.start(), m.end())); 13 assertFalse(m.find()); 14 } 分组Capturing groups • In regex, parentheses are used for grouping, but they also capture (keep for later use) anything matched by that part of the pattern – Example: ([a-zA-Z]*)([0-9]*) matches any number of letters followed by any number of digits – If the match succeeds, \1 holds the matched letters and \2 holds the matched digits – In addition, \0 holds everything matched by the entire pattern • Capturing groups are numbered by counting their opening parentheses from left to right: – ((A)(B(C))) 12 3 4 \0 = \1 = ((A)(B(C))), \2 = (A), \3 = (B(C)), \4 = (C) • Example: ([a-zA-Z])\1 will match a double letter, such as letter JAVA中的regex group和replace 01 @Test 02 public void testBasicGroup() { 03 Pattern p = Pattern.compile("((\\d+)\\s+(boys|girls))"); 04 05 String text = "There are total 15 boys and 12 girls in class 1."; 06 Matcher m = p.matcher(text); 07 assertTrue(m.find()); 08 assertEquals("15 boys", m.group(1)); 09 assertEquals("15", m.group(2)); 10 assertEquals("boys", m.group(3)); 11 assertTrue(m.find()); 12 assertEquals("12 girls", m.group(1)); 13 assertEquals("12", m.group(2)); 14 assertEquals("girls", m.group(3)); 15 assertFalse(m.find()); 16 } 17 18 @Test 19 public void testReplace() { 20 String text = "There are total 15 boys and 12 girls in class 1."; 21 String replacedText = text.replaceAll("(\\d+)\\s+boys", "$1 men"); 22 assertEquals("There are total 15 men and 12 girls in class 1.", replacedText); String类中的正则 – – – – – public boolean matches(String regex) public String replaceFirst(String regex, String replacement) public String replaceAll(String regex, String replacement) public String[ ] split(String regex) public String[ ] split(String regex, int limit) • If the limit n is greater than zero then the pattern will be applied at most n - 1 times, the array's length will be no greater than n, and the array's last entry will contain all input beyond the last matched delimiter. • If n is non-positive then the pattern will be applied as many times as possible Matcher类中的方法 • If m is a matcher, then – m.replaceFirst(replacement) returns a new String where the first substring matched by the pattern has been replaced by replacement – m.replaceAll(replacement) returns a new String where every substring matched by the pattern has been replaced by replacement – m.find(startIndex) looks for the next pattern match, starting at the specified index – m.reset() resets this matcher – m.reset(newText) resets this matcher and gives it new text to examine (which may be a String, StringBuffer, or CharBuffer) REGEX cont. Special Characters \n New line \r Carriage return \t Tab \v Vertical tab \f Form feed \xxx Octal character xxx \xhh Hex character hh Pattern Modifiers g Global match i Case-insensitive m Multiple lines s Treat string as single line x Allow comments and white space in pattern e Evaluate replacement U Ungreedy pattern Assertions String Replacement(有的实现使用\替代$) ?= Lookahead assertion $n nth non-passive group ?! ?<= Negative lookahead Lookbehind assertion $2 "xyz" in /^(abc(xyz))$/ $1 $` $' "xyz" in /^(?:abc)(xyz)$/ Before matched string After matched string $+ $& Last matched string Entire matched string ?!= or ?<! Negative lookbehind ?> ?() ?()| Once-only Subexpression Condition [if then] Condition [if then else] ?# Comment RegexBuddy 练习 1) 匹配字母,数字和减号 Letters, digits and hyphens 2) 匹配日期 yyyy-mm-dd 3) jpg, gif或png图片文件名 4) Email地址 5) Html tags 6) 至少包括一个大写字母、小写 字母和数字(密码强度) Scalable language Pragmatic runs on the JVM Martin Odersky Since Seamless Java interoperability Statically typed 2003 Production Hybrid ready “I can honestly say if someone had shown me the Programming Scala book by Martin Odersky, Lex Spoon & Bill Venners back in 2003 I'd probably have never created Groovy.“ James Strachan, creator of Groovy “If I were to pick a language to use today other than Java, it would be Scala.” James Gosling Who uses Scala already 一切值都是对象的实例 • JVM中的原生类型是对象的实例 • 函数也是值,从而也是对象的实例 • 123.toByte "1".toInt true.toString val compare = (x: Int, y: Int) => x > y compare(1, 2) // result: Boolean = false Java的static方法和域再没有存在的理由,因为它们的所有者 也必须是对象的实例(值),所以有了Scala中的单例object object Dog { val whatever = "dog" // static field in Java } class Dog { def callWhatever = Dog.whatever } 函数作为值 • 可以当作参数传递 • 不管它是实例的方法 • • val compare = (x: Int, y: Int) => x > y list sortWith compare class AComparator { def compare(x: Int, y: Int) = x > y } list sortWith (new AComparator).compare 还是匿名子句 object annonymous extends scala.Function2[Int, Int, Boolean] { override def apply(x: Int, y: Int) = x > y } list sortWith annonymous 没有了sta&c域,一切函数,包括object的方法调用现在都是 值(实例)的方法 一切操作都是函数调用(1) • 只有一个参数或零个参数的方法在调用时可以省略”.”和”()” • 参数也可以是一系列操作 {...} • • 1.+(1) 1 + 1 1.>(0) 1 > 0 (1 > 0).&(2 > 1) (1 > 0) & 2 > 1 stack.push(10) stack push 10 stack.pop stack pop stack push { val a = 1 val b = 2 a +b } 更多的符号需要用作方法名 def !@#%^&*\-<=>?|~:/ = println("noop") def √(x: Double) = Math.sqrt(x) val Π = Math.Pi val r = √(9*Π) ‘<’, ‘>’更适合作方法名,所以用’[’和‘]’来表示类型参数 一切操作都是函数调用(2) • for语句是函数调用 for (i <- List(1, 2)) { println(i) } List(1, 2) foreach {i => println(i)} for (i <- List(1, 2)) yield { i + 10 } List(1, 2) map {i => i + 10} • 更多的例子 • 额外的好处:自左向右顺序书写语句 // synchronized is function call instead of keyword def check = synchronized { // isInstanceOf is function call instead of keyword 100.isInstanceOf[String] } stack.pop.asInstanceOf[Int] // (Integer) stack.pop() in Java 一切操作都返回值 • 默认返回最后一条语句的值,也可以用return显式返回 val r1 = { // return 3 val a = 1 val b = 2 a + b } val r2 = if (true) 1 else 2 val r3 = // return (): Unit for (i <- List(1, 2)) { println(i) } val r4 = // return List(11, 12) for (i <- List(1, 2)) yield { i + 10 } val r5 = try { val f f } catch case } // return java.io.File = new File("afile") { ex: IOException => null Higher Level // Java – Check if string has uppercase character boolean hasUpperCase = false; for(int i = 0; i < name.length(); i++) { if(Character.isUpperCase(name.charAt(i))) { hasUpperCase = true; break; } } // Scala val hasUpperCase = name.exists(_.isUpperCase) Declaring classes …concisely // Scala class Person( var name: String, var age: Int ) // Java public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } } Scala – Pattern Matching Java – working with Person Object x = new Person("Bill Clinton", 64); var x: Any = Person("Lukasz", 28); if(x instanceof Person) { x match { Person p = (Person)x; case Person(name, age) => System.out.println(„Person name: "+p.getName()); println("Person name: "+name); } else { case _ => println("Not a person") System.out.println("Not a person"); } } x = "Lukasz Kuczera" x = "Lukasz Kuczera"; x match { if(x instanceof Person) { case Person(name, age) => Person p = (Person)x; println("Person name: "+name) System.out.println("hello "+p.getName()); case "Bill Clinton" => println("hello Bill") } else if(x instanceof String) { case s: String => println("hello "+s) String s = (String)x; if(s.equals("Bill Clinton")) case _ => "err, ???" } System.out.println("Hello Bill"); else System.out.println("hello: "+s); } else System.out.println("err, ???"); Person name: Lukasz hello Lukasz Kuczera Pattern matching …is concise // Scala reactions += { case m: MouseEntered => println(“I see it!”) case m: MouseExited => println(“Lost it.”) case m: MouseClicked => println(“Poked!”) } // Java button.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseEntered(MouseEvent e) { System.out.println(“I see it!”); } public void mouseExited(MouseEvent e) { System.out.println(“Lost it.”); } public void mouseClicked(MouseEvent e) { System.out.println(“Poked!”); } } // ...alternative - isinstanceof Working with arrays // Java public class Partition { Person[] all; Person[] adults; Person[] minors; { ArrayList<Person> minorsList = new ArrayList<Person>(); ArrayList<Person> adultsList = new ArrayList<Person>(); for(int i=0; i<all.length; i++ ) { (all[i].age<18 ? adultsList: minorsList).add(all[i]); } minors = (Person[]) minorsList.toArray(); adults = (Person[]) adultsList.toArray(); } } // Scala val all: Array[Person] val (minors, adults) = all.partition(_.age<18) Duck Typing class Duck { def quack = "呱...呱..." } def doQuack(d: {def quack: String}) { println(d.quack) } doQuack(new Duck) Nice to know Scala: Java: Console.println(“Hello”) println(“Hello”) System.out.println(“Hello”); val line = Console.readLine() val line = readLine() BufferedReader r = new BufferedReader(new InputStreamRead(System.in) String line = r.readLine(); error(“Bad”) throw new RuntimeException(“Bad”) 1+1 1 .+(1) new Integer(1).toInt() + new Integer(1).toInt(); 1 == new Object 1 eq new Object new Integer(1).equals(new Object()); new Integer(1) == new Object(); """A\sregex""".r java.util.regex.Pattern.compile(“A\\sregex”); “A little learning is a dangerous thing; drink deep, or taste not the Pierian spring: there shallow draughts intoxicate the brain, and drinking largely sobers us again.” --Alexander Pope 学识浅薄是件危险的事情; 要么酣饮,不然就尝不到知识源泉的甘霖。 在那里浅斟薄饮使头脑醉昏, 大量畅饮会使我们清醒。 --亚历山大·蒲柏