java: part i · using streams (java 8) •from java 8 onward we can convert collections to streams...
TRANSCRIPT
Java: part IIJef De Smedt
Beta VZW
1
Course contents
• Java SE vs Java EE
• Enums
• Generics
• Collections
• Anonymous classes
• JDBC
• File Input/Output
• Multithreading
• Distributed systems
3
Java SE vs Java EE
• Java Standard Edition• Core Java functionality: console applications, GUI (Windows Applications),
access to databases, low level networking
• Suited for Single machine applications and simple network applications
• Java Enterprise Edition• Extension to Java SE
• Client-Server applications: web applications (Servlet, JSP, JSF), important business layer
• Java Micro Edition• Older smartphones, not important anymore (no Android or IOS)
4
Enums
• An Enum is a type that is used when we have a limited number of values:
enum Season {SUMMER, AUTUMN, WINTER, SPRING};
• We can get all the values:
Season[] values = Season.values();
• We can convert from String to Season:
Season favorit = Season.valueOf(myseason.toUpperCase());
• We can convert from Season to int
int n = favorit.ordinal()
5
Generics
• New in Java 5
• Templates in C++ (not completely the same)
• Often used in collections
• Collection of Objects vs Collections of specific type
• ArrayList vs ArrayList<String>
• => add(Object) vs add(String)
6
Generics (generics01)
public class Main {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
@SuppressWarnings("rawtypes")
ArrayList list1 = new ArrayList();
list1.add("Elvis"); // add a String
list1.add(42);// add a number
list1.add(new Person("Elvis", 42)); // add a person
for (Object o: list1) {
System.out.println(o);
}
}
}
7
Generics(generics02)
public class Main {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<String>();
list1.add("Elvis");
//list1.add(42); //not possible
//list1.add(new Person("Elvis", 42)); //not possible
for(String s:list1) {
System.out.println(s);
}
}
}
8
Generics(generics03)
• Create your own generic class Trap
public class Trap<E> {private E prisoner;public void catchPrisoner(E prisoner) {
this.prisoner = prisoner;}public E releasePrisoner() {
E tmpPrisoner = this.prisoner;this.prisoner = null;return tmpPrisoner;
}/*public String getPrisonerName() {* //impossible, not every class has a getName() method*return prisoner.getName();
}*/}
9
Generics(generics03)
• Use the class:public static void main(String[] args) {
Trap<Bear> bearTrap = new Trap<Bear>();
Bear baloo = new Bear("Baloo");
Duck donald = new Duck("Donald");
bearTrap.catchPrisoner(baloo);
Animal a = bearTrap.releasePrisoner(); //Animal is base class
System.out.printf("%s is released", a.getName());
//error: bearTrap cannot catch ducks
//bearTrap.catchPrisoner(donald);
}
10
Generics (generics04)
• Suppose we have classes Animal, Bear and Duck
class Animal{private String name;public Animal(String name) {
this.name = name;}public String getName() {
return name;}
}class Bear extends Animal{
public Bear(String name) {super(name);
}}class Duck extends Animal{
public Duck(String name) {super(name);
}}
11
Generics (generics04)
• Now we can create a Trap that only works with animals
public class AnimalTrap <E extends Animal> {private E prisoner;public void catchPrisoner(E prisoner) {
this.prisoner = prisoner;}public E releasePrisoner() {
E tmpPrisoner = this.prisoner;this.prisoner = null;return tmpPrisoner;
}public String getPrisonerName() {//Every prisoner is an Animal with a getName() method
return prisoner.getName(); }
}
12
Generics backward compatibility(generics05)
• Suppose we have a library that uses a non-generic ArrayList
• How can we use this in our (generic ArrayList) program?
• => @suppresswarnings(“unchecked”)
• Explanation: it would generate a compiler warning (not an error) because the compiler cannot assure the type safety. We simply suppress the warning
@SuppressWarnings("unchecked")
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
Members members = new Members();
list.addAll(members.getMembers()); // public ArrayListgetMembers()
}
13
Generics “erasure”
• Java bytecode (compiled code) does not recognize generic types
• ArrayList<String> will be a simple ArrayList in bytecode => genericinformation is “erased” (hence “erasure”)
• Compiler will add the necessary casts to assure typesafety => e.g. list.add(s) might become list.add((String)s)
14
Collections
• We have already seen an ArrayList in the previous examples
• An arraylist is an example of a collection (group of items)
• Java has different types of collections
• Collections form a hiërarchy in Java
15
16
<<interface>Iterable
<<interface>Collection
<<interface>List
<<interface>Set
ArrayList LinkedList HashSet TreeSet
Ordered items with anindexed position
unique items, no indexed position
Iterable<E>/Iterator<E> interface(1)
• Iterable objects can be fetched one-by-one (“enumerated”)
• Iterable interface has one method: iterator() (returns Iterator)
• Iterator interface has three methods:• boolean hasNext() //checks whether there is a next
• T next() //fetches next item
• void remove() //removes current item
17
Iterable<E>/Iterator<E> interface(2)
• Typical usage:
Iterable<String> col = … // collection initialized here
Iterator<String> it = col.iterator();
while(it.hasNext()){
String s = it.next();
System.out.prinlnt()
}
18
Collection<E> interface
• Collections manage a group of items
• Among others it defines the following methods• boolean add(E item): add an item
• void clear(): removes all elements
• boolean contains(Object o): does the collection contain the object
• Iterator<E> iterator(): inherited from Iteratable interface
• boolean remove(object o): removes an object
• int size(): returns the number of items in the collection
• Object[] toArray(): returns the collection as an array
19
List<E> interface
• A List is a Collection where each item has a position (just like an array)
• Among others it defines the following methods• boolean add(E items): inherited from Collection, adds an item to the end of the
collection• void add(int index, E item): insert an item at a position• E get(int index): returns the element at the specified position• int indexOf(Object o): returns the position of the first occurence of the object• Iterator<E> iterator(): inherited from Iteratable interface• int lastIndexOf(Object o): returns the position of the last occurence of the object• boolean remove(object o): removes an object• E set(int index, E item): replaces the item at the position• Object[] toArray(): returns the collection as an array
20
Collection01: using collections
Collection<String> building = new ArrayList<>();
building.add("Elvis");
if(building.contains("Elvis")) {
System.out.println("Elvis is in the building");
} else {
System.out.println("Elvis has left the building");
}
if (building.isEmpty()) {
System.out.println("The building is empty");
} else {
System.out.println("There is someone in the building");
}
21
Collection01: using collections and iterator
building.add("Priscilla");
Iterator<String> it = building.iterator();
while (it.hasNext()) {
String name = it.next();
System.out.println(name);
}
//When a class has an iterator, we can use a for each
for (String s: building) {
System.out.println(s);
}
building.clear();
22
Using streams (Java 8)
• From Java 8 onward we can convert collections to streams
• Streams can use lambda functions to manipulate data
• E.g.: .filter(e -> e.getDepartment().equals(“Accounting”))
23
e is an objectWhen this statement is true, the object goes to the next
step in the stream
Collection02: employee class
24
public class Employee {
private String name, department;
public Employee(String name, String department) {
this.name = name;
this.department = department;
}
public String getName() {
return name;
}
public String getDepartment() {
return department;
}
}
Collection02: main method
public static void main(String[] args) {
Collection<Employee> company = new ArrayList<Employee>();
company.add(new Employee("Elvis", "Entertainment"));
company.add(new Employee("Priscilla", "Accounting"));
company.add(new Employee("Colonel Parker", "Management"));
company.add(new Employee("Lisa Marie", "Accounting"));
//Java 8
company.stream()
.filter(e -> e.getDepartment().equals("Accounting"))
.forEach(e -> System.out.println(e.getName()));
}
25
For each object execute this statement
Collection03: set (unique items)
public static void main(String[] args) {
Set<String> items = new HashSet<String>();
items.add("Elvis");
boolean succeeded = items.add("Elvis"); // false
if (!succeeded) {
System.out.println("There is only one Elvis");
}
System.out.println("The set contains " + items.size() + " elements");
}
26
The set will contain 1 element
Collection04: unique objects?public static void main(String[] args) {
Set<Employee> items = new HashSet<Employee>();
items.add(new Employee("Elvis"));
boolean succeeded = items.add(new Employee("Elvis")); //true!!!
if (succeeded) {
System.out.println("There is an Elvis impersonator here");
}
Iterator<Employee> it = items.iterator();
while(it.hasNext()) {
Employee e = it.next();
if (e.getName().equals("Elvis")) it.remove();
}
System.out.println("The set contains " + items.size() + " elements");
}
27
Collection04: we must override the equalsmethod
public class Employee {
private String name;
public Employee(String name) {
this.name = name;
}
public String getName() {
return name;
}
28
This is not enough code to let a set check whether two employees are equal or not
Collection04: we must override the equalsmethod
@Override
public boolean equals(Object o) {
boolean equal = false;
if (o instanceof Employee) {
Employee e = (Employee)o;
equal = this.getName().equals(e.getName());
}
return equal;
}
@Override
public int hashCode() {
return name.hashCode();
}
29
My definition is: two employees are equal when they have the same name
When two objects are equal they must have the same hashcode
Collection05: listspublic static void main(String[] args) {
List<String> items = new ArrayList<String>();
items.add("Elvis"); // position 0
items.add("Colonel Parker"); // position 1
items.set(1, "Dries Van Kuijk"); // replace element 1
items.add("Vernon");
int index = items.indexOf("Elvis");
System.out.println("Elvis is on position " + index);
items.remove(1);
String name = items.get(1); //Vernon is shifted to position 1
System.out.println("On position 1 we have " + name);
ListIterator<String> it = items.listIterator(items.size());
while (it.hasPrevious()) {
System.out.println(it.previous());
}30
Collection06: mappublic static void main(String[] args) {
String[] words = {"one", "two", "one", "three", "three", "one"};
Map<String, Integer> frequency = new HashMap<String, Integer>();
for(String word: words) {
Integer freq = frequency.get(word);
if (freq == null) {
freq = 1;
} else {
freq = freq + 1;
}
frequency.put(word, freq);
}
System.out.println(frequency);
}
31
Anonymous classes
• Suppose we have an interface:
• Then we can define a class that implements the interface
32
interface Command{
void execute();
}
class MenuItem implements Command{
@Override
public void execute() {
System.out.println("Hi all");
}
}
Anonymous class
• And we can create an object of that class and use it
• But this class will only be used once, because it is a very specificmenu-item with a very specific command
33
MenuItem item1 = new MenuItem();
item1.execute();
Anonymous class
• As an alternative we can create a class “on the fly”
• The object is created based on a class that has no name (anonymousclass)
• We can use an anonymous class when the class will only be used once
34
Command item2 = new Command() {
@Override
public void execute() {
System.out.println("By all");
}
};
Anonymous class: Comparator interface
• We can sort a collection by using Collections.sort(collection):
Collections.sort(people);
• But as a second argument we can give a comparator object. A Comparator object has one method: compare(item1, item2)
• The method must return -1, 0, 1 when the first object is less than, equal to or greater than the second object
35
Anonymous class: Comparator interface
Collections.sort(people, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.substring(1).compareTo(o2.substring(1));
}
});
36
Lambda expressions
• When an interface only has one method(functional interface) it canbe written as a lambda function
Collections.sort(people,(o1, o2) ->
o1.substring(1).compareTo(o2.substring(1)));
• A lambda expression has • Arguments: (o1, o2)
• A lambda operator: ->
• A return value: o1.substring(1).compareTo(o2.substring(1)));
37
Lambda and streams
students.stream()
.filter(s -> s.getAge() >= 15 )
.sorted((s1, s2)->s1.getName().compareTo(s2.getName()))
.limit(2)
.forEach(s -> System.out.println(s));
//alternative: .foreach(System.out::println)
38
Get students with age>= 15
Sort them by name
Only take the first two
Print each one of them
Java databases: jdbc
• To connect to a database we use a driver for the database
• Java Database Connection (JDBC) defines 4 driver types:• Type 1: a jdbc driver with a mapping to another protocol (mainly ODBC)
• Type 2: a jdbc driver with java code and native code (needs a native clientlibrary
• Type 3: a pure java client driver that connects to a middleware server withdatabase independent protocol
• Type 4: a pure java driver with database specific protocol
• Most popular databases have a Type 4 driver. (Oracle, MySQL, MSSQL, DB2, …)
39
Java databases: derby
• From Java 7 onward javadb(a very simple database written in Java, not suited for production servers) is part of the Java Development Kit
• We can download the same database from apache derby (search forapache derby in google) : http://apache.cu.be/db/derby/db-derby-10.11.1.1/db-derby-10.11.1.1-bin.zip
• Unzip and put lib/derby.jar in the classpath of the application
40
Java databases: 4 ways to run Derby
1. Embedded in memory: derby is started by the application, database is created in memory (database dropped when application stops)
2. Embedded in filesystem: derby is started by the application, database is created in the file system (database is stored in the file system between different invocations)
3. Network in memory: Derby is started separate from the application(can be shared between different applications), but database disappears after stopping Derby
4. Network in filesystem: Derby is started separate from the application, database is stored in the file system after derby is stopped
41
Java databases: Derby connection strings
• Create embedded database in memory: jdbc:derby:memory:sample;create=true
• Create embedded database in file system: jdbc:derby:sample;create=true
• Connect to networked derby and create in memory database:jdbc:derby://localhost:1527/memory:sample;create=true
• Connect to networked derby and create database in file system:jdbc:derby://localhost:1527/sample;create=true
• If the database already exists: skip ;create=true
42
Java databases: template
• To connect to a database we need a java.sql.Connection
• For that we use de getConnection factory method of java.sql.DriverManager:conn = DriverManager.getConnection(“jdbc:derby:memory:sample;create=true”); //inmemory embedded database
• We can use the same method to remove the database:DriverManager.getConnection("jdbc:derby:memory:sample;drop=true");
• This last command will cause an SQLException with SQLState “08006” (catch exception => is no error)
• We also need the library derby.jar (DERBY_HOME\lib\derby.jar)
43
Java database: template (jdbc01)
• Resource protection block: whatever happens, connection must beclosed and database must be removed => try{…}finally{…}
Connection conn = null;
try{
conn =
DriverManager.getConnection("jdbc:derby:memory:sample;create=true");
System.out.println("Connected to database");
}finally{
if (conn != null) {
conn.close();
}
}
44
Java database: alternative template (jdbc01bis)• Try-with-resources is exactly the same
try (Connection conn
=DriverManager.getConnection("jdbc:derby:memory:sample;create=true")){
System.out.println("Connected to database");
}
45
Derby network database (derbyclient.jar)
• To start the derby database useDERBY_HOME\bin\startnetworkserver.bat
• Add DERBY_HOME\lib\derbyclient.jar to the classpath of the project
• Create a connection object that creates the database (will issue warning, not error, when the database already exists)
• Create a statement object that can execute SQL statements
46
Create table: jdbc02
public class Main {
private static final String CONN = "jdbc:derby://localhost:1527/sample;create=true"
private static final String CREATEPERSON = "CREATE TABLE person (id intPRIMARY KEY, name VARCHAR(50))";
private static final String INSERTPEOPLE = "INSERT INTO person VALUES (1, 'Peter'), (2, 'Paul'), (3, 'Mary')";
public static void main(String[] args) throws SQLException {
try(Connection conn=DriverManager.getConnection(CONN);
stmt.executeUpdate(CREATEPERSON);
stmt.executeUpdate(INSERTPEOPLE);
}
}
}
47
Check whether table exists
• If the program does not give an error => table should be created
• We can check this with the ij-tool (DERBY_HOME\bin\ij.bat
C:\javadb\bin>ijij version 10.11ij> connect 'jdbc:derby://localhost:1527/sample';ij> select * from person;ID |NAME--------------------------------------------------------------1 |Peter2 |Paul3 |Mary
3 rows selectedij>
48
Using resultset: jdbc03
• A CREATE TABLE statement is a “fire-and-forget” statement => we do not need a result (except for an exception when the statement fails)
• A SELECT statement returns a result.
• statement.executeQuery(“….”) executes a query (SELECT)
• The returnvalue is a ResultSet
• A resultset can be compared to an inmemory table
• Advance to the next row in the table: ResultSet.next() (returns false ifat end of resultset)
• ResultSet.getXXX(columnNumber) returns the value of a “column”
49
Resultset: one value (jdbc03)
private static final String COUNT = "SELECT COUNT(*) FROM PERSON";
private static final String CONN = "jdbc:derby://localhost:1527/sample"
public static void main(String[] args) throws SQLException {
try(Connection conn= DriverManager.getConnection(CONN);
Statement stmt = conn.createStatement()){
try(ResultSet rs= stmt.executeQuery(COUNT)){
rs.next(); // go to the first (and only) row
//row contains one column with an integer
int number = rs.getInt(1);
System.out.printf("TABLE contains %d people\n", number);
}
}
}
50
Resultset with more values (jdbc03)
private static final String SELECT = "SELECT * FROM PERSON";public static void main(String[] args) throws SQLException {
try(…){ …
try(ResultSet rs = stmt.executeQuery(SELECT)){
while(rs.next()) {
int id = rs.getInt(1);
String name = rs.getString(2);
System.out.printf("%d: %s\n", id, name);
}
}
}}
51
Prepared statement (jdbc04)
• INSERT, UPDATE and DELETE statements can be executed with the executeUpdate() method.
• But these statements often contain a static and an dynamic part:• Delete from person where id=1
• Delete from person where id=2
• …
• A database can compile the static part (prepare) and execute the statement with different dynamic parts
• For this we use a prepared statement
52
Prepared statement(jdbc04)
private static final String CONN ="jdbc:derby://localhost:1527/sample";
private static final String INSERT = "INSERT INTO PERSON (id, name) VALUES (?,?)";
public static void main(String[] args) throws SQLException {
Person[] persons = {new Person(4,"Elvis"), new Person(5, "Lisa Marie")};
try(Connection conn = DriverManager.getConnection(CONN)){
try(PreparedStatement prepstmt = conn.prepareStatement(INSERT)){
for(Person p:persons) {
prepstmt.setInt(1, p.getId()); // first ?
prepstmt.setString(2, p.getName()); // second ?
prepstmt.executeUpdate();
}
}
53
Autonumbering fields (jdbc05)
• In Derby we create a table with an autonumbering field with the following SQL statement:private static final String CREATE = "CREATE
TABLE products (id int generated always as
identity primary key, name varchar(50), price
decimal)";
• The database will provide the value for ID => no insert ID:private static final String INSERT = "INSERT
INTO products (name, price) VALUES (?, ?)";
54
Autogenerated keys (jdbc05)
• We ask to return the generated keys in prepareStatement• getGeneratedKeys returns a resultset with the keyspstmt = conn.prepareStatement(INSERT, PreparedStatement.RETURN_GENERATED_KEYS);pstmt.setString(1, "Pencil");pstmt.setBigDecimal(2, new BigDecimal(10));pstmt.executeUpdate();rs = pstmt.getGeneratedKeys(); // get generated idif (rs.next()) {int id = rs.getInt(1);System.out.printf("Pencil added with key %d\n",
id);
55
Rowsets
• The capabilities of a resultset depend on the capabilities of the driver
• Some drivers let you create scrollable resultset (scroll back and forth)
• Rowset add this extra capability to drivers that do not support thisnatively (JdbcRowset)
• We can also use CachedRowsets that let you work without a connection to the database
56
JdbcRowset(jdbc06)
• A JdbcRowset can be constructed from a Connection
• Using a JdbcRowset we can scroll backward in a tableconn = DriverManager.getConnection("jdbc:derby://localhost:1527/sample");
jdbcRs = new JdbcRowSetImpl(conn);
jdbcRs.setCommand(SELECT);
jdbcRs.execute();
jdbcRs.last(); // goto last row in rowset
while (!jdbcRs.isBeforeFirst()) {
int id = jdbcRs.getInt(1);
String name = jdbcRs.getString(2);
System.out.printf("%d: %s\n", id, name);
jdbcRs.previous();
}
57
JdbcRowset(jdbc07)
• A JdbcRowset can also be constructed from a connectionstring
• A JdbcRowset is updateable: we can insert a row (we have to move to the insertrow first)
• Adding new values is done by using the updatexxx() methods
• The insert in the database is done with insertRow()jdbcRs = new JdbcRowSetImpl();
jdbcRs.setUrl("jdbc:derby://localhost:1527/sample");
jdbcRs.setCommand(SELECT);
jdbcRs.execute();
jdbcRs.moveToInsertRow();
jdbcRs.updateInt(1, 4);
jdbcRs.updateString(2, "Elvis");
jdbcRs.insertRow();
jdbcRs.moveToCurrentRow();// move back to the row we were on
58
JdbcRowset: update and delete
• Updating values in a Rowset is comparable to inserting rows
• We do not have to move to the insertrow, the current row is updated
• After updating the currentrow we have to call updateRow() to writethe new values to the database
• We can cancel the changes by calling cancelRowUpdates() (instead of updateRow())
• To delete a row we call deleteRow(): the current row is deleted in the database.
59
CachedRowset
• A JdbcRowset only works when there is an (open) connection to a database.
• A CachedRowset copies the values from the database to an in-memory table
• We can change the values in the in-memory table
• Afterwards we can copy the changes to the database (acceptChanges())
• To update the right rows in de database the rowset has to know the unique key for every row (setKeyColumns())
60
CachedRowset(jdbc08)
• We define a CachedRowset with a command and a definition of the unique columns (because we also want to update)crs = new CachedRowSetImpl();
crs.setCommand("SELECT * FROM person");
crs.setKeyColumns(new int[] { 1 }); // Define primary keys
• Next we can read the data, for this we need an open connection
• After reading we can close the connectionprivate static void readData(CachedRowSet crs) throws SQLException{
try(Connection conn = DriverManager.getConnection(CONN) ) {
crs.execute(conn);
}
}
61
CachedRowset(jdbc08)
• We do not need an open connection to change the dataprivate static void doubleName(CachedRowSet crs) throws SQLException {
for (crs.first(); !crs.isAfterLast(); crs.next()) {
String name = crs.getString(2);
name = name + name;
crs.updateString(2, name);
crs.updateRow(); //does not write to the database
}
}
• This updates the in-memory table, in the database nothing is changed(yet)
62
CachedRowset(jdbc08)
• To write the changes to the database we need an open connection
• The method acceptChanges() writes all the changes to the databaseprivate static void writeData(CachedRowSet crs) throws
SQLException,SyncProviderException {
try(Connection conn = DriverManager.getConnection(CONN)) {
crs.acceptChanges(conn);
}
}
• The method acceptChanges() can throw a SyncProviderExceptionwhen the underlying data has changed
63
CachedRowset: optimistic concurrency
• Rows in a database are not locked while a CachedRowSet is used
• => value in database may be changed by another user while someoneis using the CachedRowSet = conflict
• The method acceptChanges will throw a runtimeException when a conflict arises: SyncProviderException
• Optimistic concurrency: “special” update statementUPDATE person SET name=‘PeterPeter’ WHERE id=1 AND name=‘Peter’
• The value is only updated when the database record has not changedin the meantime
64
CachedRowset: optimistic concurrency(jdbc09)• We start with catching the exception:try {crs = new CachedRowSetImpl();crs.setUrl("jdbc:derby://localhost:1527/sample");crs.setCommand("SELECT * FROM person");crs.setKeyColumns(new int[] { 1 });crs.execute();System.out.print("Hit <RETURN> key");scanner.nextLine(); // change data in database (ij-tool)doubleName(crs);crs.acceptChanges();
} catch (SyncProviderException ex) {resolveConflict(crs, ex);
} finally {if (crs != null)crs.close();
}
65
CachedRowset: optimistic concurrency(jdbc09)• A SyncResolver is a rowset with a row for every update that did not
succeed
• We go to the next row with nextConflict()
• Because we want to show the value in the rowset we also positionthe cachedrowsetprivate static void resolveConflict(CachedRowSet crs,
SyncProviderException ex) throws SQLException {
SyncResolver resolver = ex.getSyncResolver();
while (resolver.nextConflict()) {
int row = resolver.getRow(); //get rownumber
crs.absolute(row); // goto to conflicting row in CachedRowSet
66
CachedRowset: optimisticconcurrency(jdbc09)• Rows that were not updated because they were after the conflicting row get a value of null for
conflictValue
switch (resolver.getStatus()) {case SyncResolver.UPDATE_ROW_CONFLICT:String nameInRowSet = crs.getString(2);Object nameInDataBase = resolver.getConflictValue(2);if (nameInDataBase != null) {System.out.printf("No update: %s(rowset) vs %s(db)\n",
nameInRowSet, nameInDataBase);} else {System.out.printf(
"%s not updated because of previous errors", nameInRowSet);}break;
case SyncResolver.INSERT_ROW_CONFLICT:case SyncResolver.DELETE_ROW_CONFLICT:System.out.println("Other conflict");break;
}
67
Internationalisation
• Internationalisation (I18N) is the process to “internationalise” applications
• That means:• Show labels, menus, … in the right language
• Show numbers and dates in the right form
• Sort according to the right collation
• Translations in java can be provided• As text file (properties)
• In a special java class
68
Internationalisation: properties files
• Example of a properties file for English(MessageBundle.properties)greetings = Hello.
farewell = Goodbye.
inquiry = How are you?
• The same file for French and Dutch(MessageBundle_fr.properties andMessageBundle_nl.properties)greetings = Bonjour.
farewell = Au revoir.
inquiry = Comment allez-vous?
greetings = Goedendag.
farewell = Tot ziens.
inquiry = Hoe gaat het met u?
69
Internationalisation(international01)
• We load a bundle for the right localepublic static void main(String[] args) {//Locale currentLocale = Locale.FRENCH;//Locale currentLocale = new Locale("nl");Locale currentLocale = new Locale(“de");// getBundle(basename, locale) loads the right locale file// if the file is not available (German), it will use the // default locale of the system and the corresponding properties // file. If the corresponding properties file for the default // locale of the systemi s not available, the base file is used //(MessageBundle.properties)ResourceBundle messages =
ResourceBundle.getBundle("MessageBundle",currentLocale);
System.out.println(messages.getString("greetings"));
System.out.println(messages.getString("inquiry"));System.out.println(messages.getString("farewell"));}
70
Internationalisation with classes (international02)• Instead of a properties file we can also use an object that returns the
key-value pairs
• The object must be of type ListResourceBundlepublic class MyBundle extends ListResourceBundle {
private Object[][] contents = {{"greetings",
"Hello"},{"farewell", "Goodbye"},{"inquiry", "How are
you?"}};
@Override
protected Object[][] getContents() {
return contents;
}
}
71
Internationalisation withclasses(international02)• The name of the class determines the locale
• French-Belgium:public class MyBundle_fr_BE extends ListResourceBundle {…}
• Dutch-Belgiumpublic class MyBundle_nl_BE extends ListResourceBundle {…}
• Usage of the bundle is the sameResourceBundle messages =
ResourceBundle.getBundle("org.betavzw.MyBundle",currentLocale);
72
Internationalisation: number and date formatting(internation03)• We can define a numberformatter to format integers and doubles:NumberFormat formatter =
NumberFormat.getNumberInstance(currentLocale);
String doubleOutput = formatter.format(pi);
String intOutput = formatter.format(answer);
• We can define a dateformatter to format dates:DateTimeFormatter dateFormatter = DateTimeFormatter
.ofLocalizedDate(FormatStyle.SHORT).withLocale(currentLocale);
LocalDate date = LocalDate.of(1935, Month.JANUARY, 8);
String dateString = dateFormatter.format(date);
73
Internationalisation: messageformatting(international03)• We can combine string and number/date formatting by defining a
messageformat:private Object[][] contents = {…{"MESSAGE_Format","PI c''est {0, number}.\n{1, number} est la réponse.\nElvis est né le {2, date, short}"},};
• Using braces we choose the position of the argument and the type (number, date)
74
Internationalisation: collation/sorting(international04)• A Collator has a compare() method to compare two strings according to a
locale:private static Collator collator = Collator.getInstance(Locale.FRANCE);public static void main(String[] args) {List<String> strings = new ArrayList<String>();strings.add("péché");strings.add("pêche");…Collections.sort(strings, new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {
return collator.compare(o1, o2);}
});for(String s: strings) {System.out.println(s);
}
75
Java I/O streams
• An I/O stream represents an input source or an output destination
• E.g.: file, network socket, memory arrays, …
• In this chapter we take a look at file streams
• The name “stream” comes from the fact that we read (or write) a stream of bytes
• Java defines different kinds of streams: bytestreams (read/write per byte/8bits) characterstreams (read/write per unicode character)
76
Java buffered I/O streams
• Reading (or writing) per byte or per character is not very efficient
• A buffered stream reads a number of bytes/characters from a streamin a buffer and flushes (writes) the buffer to the stream
• A buffered stream uses the decorator design pattern: its constructorneeds a character or byte stream:BufferedReader reader = new BufferedReader(new FileReader("a.txt"));
• When we read from a BufferedReader the reader reads from the underlying stream to fill the buffer. All subsequent read-operations come from the buffer until the buffer is empty and new data is read from the stream again.
77
Java PrintWriter/Stream(FileIO01)
• A PrintWriter writes to a character stream
• A PrintStream writes to a bytestream
• System.out is an example of a PrintStream
• Println(), Print() and Printf() are typical PrintWriter/PrintStreammethods
78
Java PrintWriter(fileIO01)
• When we use a file we should always close the filestream
Scanner scanner = new Scanner(System.in);
try(PrintWriter writer = new PrintWriter(new
FileWriter("out.txt"))) {
String line;
System.out.println("Give line (end with empty line)");
while(!"".equals(line = scanner.nextLine())) {
writer.println(line);
}
System.out.println("<TERMINATED PROGRAM>");
}
79
Java BufferedReader(fileIO02)
• We read the file we have written in the previous exampletry(BufferedReader reader = new BufferedReader(new
FileReader("../fileIO01/out.txt"))){
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
• (in fact System.out is also a BufferedReader)
80
Writing objects(fileIO03)
• We can dump(write) objects to streams, provided they are Serializable
• In order to be Serializable they must implement the Serializableinterface
• In order to implement Serializable the class can only contain primitivetypes or other Serializable member variables:public class Person implements Serializable {
private static final long serialVersionUID = 1L;private String name;private int age;…
}
81
Writing objects(fileIO03)
• Using an ObjectOutputStream and the writeObject() method we canstream objects:ArrayList<Person> persons = new ArrayList<Person>();
persons.add(new Person("Elvis", 79));
persons.add(new Person("Priscilla", 69));
try (ObjectOutputStream out = new ObjectOutputStream(new
FileOutputStream("persons.bin"))){
out.writeObject(persons);
System.out.println("<Program terminated>");
}
82
Reading objects(fileIO04)
• When we know which objects are available we can read them from anObjectInputStream (using the right cast and the right SerialVersionUID in the Person class):List<Person> persons = null;
try(ObjectInputStream in = new ObjectInputStream(new
FileInputStream("../fileIO03/persons.bin"))){
persons = (List<Person>)in.readObject();
for (Person p: persons){
System.out.printf("%s: %s\n", p.getName(), p.getAge());
}
}
83
Multithreading(concurrency)
• A console application has one thread of execution: all statements are executed in sequence.
• We can start a second thread of execution: statements can beexecuted in parallel.
• Multithreading can improve the responsiveness of a program: executing long running tasks in a separate thread while the mainthread processes the user commands. (GUI programs)
• Multithreading is often used in server applications (multiple clientsare handled in parallel)
• Multithreading can complicate a computer program.
84
Multithreading: thread states
85
New
Ready
Running
Terminated BlockedWait/Sleep
start()
dispatched by Operating SystemTime slice expired
End thread
I/O operation
I/O completed
sleep()join()lock
notify()Other thread has stoppedDone sleeping
Multithreading: multithread01
• Code that has to be executed must be in a method
• Method must be part of class that extends Thread or implementsRunnable
• Interface Runnable contains one method: run()
• Because a thread can be interrupted, the run()-method must catch the InterruptedException
86
Multithreading: multithread01
• We define a class that implements Runnable
public class ThreadRunner implements Runnable {private String name;public ThreadRunner(String name) {
this.name = name;}@Overridepublic void run() {
try {for (int i = 0; i < 5; i++) {
System.out.println("Running " + name);Thread.sleep(1000);
}} catch (InterruptedException e) {// InterruptedException when an another thread interrupts this thread
e.printStackTrace();}
}
}
87
Multithreading: multithread01
• First we execute the run()-methods in sequence
• Then we execute them in different threads
public static void main(String[] args) {ThreadRunner tr1 = new ThreadRunner("TR1");ThreadRunner tr2 = new ThreadRunner("TR2");System.out.println("Both 'threads' run in main thread");tr1.run();tr2.run();System.out.println("Both 'threads' run in different thread");Thread t1 = new Thread(new ThreadRunner("TR1"));Thread t2 = new Thread(new ThreadRunner("TR2"));t1.start(); //invokes run() method from Runnablet2.start();System.out.println("End of program (will end before TR1 and
TR2)");
}
88
Multithreading: multithread02
• Concurrent threads can interfere with each other when they update the same value at the same time
• AtomicInteger can solve this problem
atomicCounter.incrementAndGet();
• This is an atomic operation: both actions (increment and get) happen as one operation
89
Multithreading: threadpools
• Until now there was a one-to-one relationship between task(run() method) and thread => for every task a new thread had to be created+ the thread was destroyed after the task was finished
• But: thread creation is an expensive operation for an operating system
• A threadpool contains a number of threads.
• When we give a task to a threadpool one of the free threads is usedto execute the task.
• When there is no free thread: task waits in a queue
• Task is finished => thread becomes a free thread again
90
Multithreading: threadpools(multithread03)
• An executor is responsible for the execution of tasks by a threadpool
• In this example we create an executor for a fixed thread pool (fixednumber of threads)
int processors = Runtime.getRuntime().availableProcessors();System.out.printf("Number of processors: %d\n", processors);
ExecutorService e = Executors.newFixedThreadPool(processors);
• We can create a list of task objects (implement Callable interface) andinvoke them using invokeAll (waits until all tasks have finished)
List<ParallelBlur> tasks = new ArrayList<ParallelBlur>();
…e.invokeAll(tasks);
91
Distributed programs
• Java EE (Enterprise Edition) is more suited for distributed systems
• Distributed system has server (listening) and client (connecting) components
• A server socket listens on a port, a client socket connects to a port
• Data between client and server is exchanged by using streams (cfrfiles)
92
Server socket(chatserver)
• A server socket blocks until a client connects
• In a real application (multiple clients) we will start a new thread toprocess the client requests
ServerSocket socket = null;
Socket client = null;
BufferedReader in = null;
PrintWriter out = null;
try {
//listen to port 8888 on localhost
socket = new ServerSocket(PORT, 0, InetAddress.getByName(null));
System.out.println("Waiting for connection...");
client = socket.accept();
93
Server socket (chatserver)
• We define a BufferedReader and a PrintWriter to read and write
• For the PrintWriter we set autoflush to true: a println() writes to the stream
//define socket reader and socket writer
in = new BufferedReader(new
InputStreamReader(client.getInputStream()));
out = new PrintWriter(client.getOutputStream(), true);
System.out.println("I have a client");
String line=null;
Scanner scanner = new Scanner(System.in);
94
Server socket(chatserver)
• Read and write data, in the end we close the sockets//read until client closes socketwhile (null != (line = in.readLine())){
System.out.println(line);System.out.print("Input: ");String answer = scanner.nextLine(); // read answer from
server userout.println(answer); //write answer to client
}} finally {
if (client != null && !client.isClosed()){client.close();
}if (socket != null && !socket.isClosed()) {
socket.close();}
}
95
Client socket(chatclient)
• A client connects to a port on a certain machine
• We define a reader and a writer
Socket client = null;PrintWriter out = null;BufferedReader in = null;try {
//Connect to server on port 8888 on localhostclient = new Socket(InetAddress.getByName(null), PORT);//define socket reader and writerout = new PrintWriter(client.getOutputStream(),true);in = new BufferedReader(new
InputStreamReader(client.getInputStream()));Scanner scanner = new Scanner(System.in);String line;System.out.print("Input: ");
96
Client socket(chatclient)
• And then we start writing and reading//send until user enters 'bye‘while (!"bye".equals(line = scanner.nextLine())) {
out.println(line); // write line to serverString answer = in.readLine(); // read line from serverSystem.out.println(answer);System.out.print("Input: ");
}} finally {
if (out != null) out.close();if (in != null) in.close();if (client != null && !client.isClosed()) {
client.close();}
}
97