ORACLEでデータを削除してしまった場合、下記のフラッシュバッククエリを使用して、時間を指定してデータを取得できる
SELECT * FROM M_ITEM AS OF TIMESTAMP TO_TIMESTAMP('20231127090000', 'YYYYMMDDHH24MISS');
DELETEで削除したデータは取得できるが、TRANCATEはUNDO領域にデータを作成しないため取得できない。
ORACLEでデータを削除してしまった場合、下記のフラッシュバッククエリを使用して、時間を指定してデータを取得できる
SELECT * FROM M_ITEM AS OF TIMESTAMP TO_TIMESTAMP('20231127090000', 'YYYYMMDDHH24MISS');
DELETEで削除したデータは取得できるが、TRANCATEはUNDO領域にデータを作成しないため取得できない。
下記のようなテキストファイルにおいて、TANAKAxxxx がIDだとする
TANAKA0001 = {name:"山田",dept:"sales"},TANAKA0002 = {name:"鈴木",dept:"sales"},TANAKA0003 = {name:"轟",dept:"sales"},TANAKA0004 = {name:"上野",dept:"sales"}
正規表現でIDの箇所だけ取得したい場合、「TANAKA.*=」で指定すると失敗する
「=」が最後に出現する箇所がTANAKA0004 =なのでここまで検索されてしまう
「TANAKA.*?=」で検索するとIDを個々で検索できる
new File("ファイル名") でFileクラスのインスタンスを作成する。
createNewFile()でインスタンス作成時の引数に指定したファイルがカレントディレクトリに作成される。
exists()でファイルが存在するか確認できる。
ファイルと同じようにnew File("ディレクトリ名")でFileクラスのインスタンスを作成する。
mkdir()でインスタンス作成時の引数に指定したディレクトリがカレントディレクトリに作成される。
exists()でディレクトリが存在するか確認できる。
どちらもgetAbsolutePath()を使うとルートディレクトリからの絶対パスが取得できる。
import java.io.File; import java.io.IOException; public class Main { public static void main(String[] args) { File file = new File("data.txt"); File dir = new File("data"); try { // ファイルが存在しなければファイルを作成 if (!file.exists()) { file.createNewFile(); System.out.println(file.getAbsolutePath()); } // ディレクトリがなければ作成 if (!dir.exists()) { dir.mkdir(); System.out.println(dir.getAbsolutePath()); } } catch (IOException e) { System.out.println(e); e.printStackTrace(); } } }
前回は関数に渡される引数を可変長にすることができるRest演算子について説明しました。
今回は配列の値を展開するSpread演算子を説明します。
Spread演算子は配列の値を展開して利用したい場合に役立ちます。
2つの配列の値を1つの配列に格納する処理を例にして説明します。
2つの配列の値を1つの配列に格納したい場合ですが、下記のメソッドのように単純に配列の中に配列を格納すると、配列「animalSeason」は配列の中に配列が格納された状態となります。
test() { const animal = ["cat","dog","lion"]; const season = ["april","summer","fall"]; const animalSeason = [animal,season]; console.log(animalSeason); }
ではSpread演算子を使用してみます。
Spread演算子はRest演算子と同様に、変数の先頭に”…”を加えることで実現できます。
配列「animal」と「season」の先頭に” …”を加えて「animalSeason」に格納しました。
メソッドを実行します。
test() { const animal = ["cat","dog","lion"]; const season = ["april","summer","fall"]; // Spread演算子を使用 const animalSeason = [...animal,...season]; console.log(animalSeason); }
「animal」と「season」の値を「animalSeason」に入れることができました。
しかし、同じような処理はconcatを使用しても実現できてしまいます。
test() { const animal = ["cat","dog","lion"]; const season = ["april","summer","fall"]; // concatを使用 const animalSeason = animal.concat(season); console.log(animalSeason); }
では、Spread演算子を利用することで何が嬉しいのでしょうか。
Spread演算子では結合したい配列のほかに、任意の値も格納することができます。
下記では「animalSeason」に直接”apple”と”orange”を格納しています。
test() { const animal = ["cat","dog","lion"]; const season = ["april","summer","fall"]; // appleとorangeを格納 const animalSeason = ["apple",...animal,"orange",...season]; console.log(animalSeason); }
このように、より柔軟に配列に値を格納することができます。
JavaScriptでは関数に渡される引数を可変長にすることができるRest演算子と、
配列の中身を展開するSpread演算子という便利な仕組みがあります。
今回はRest演算子について説明します。
Vueのソースコードで説明していきます。
下記のコードではrestSampleメソッドが定義しています。引数を5つ指定していて、引数で受け取った値をconsoleに出力する単純な処理です。
<template> <div> <button @click="restSample(1,2,3,4,5)">test</button> </div> </template> <script> methods: { restSample(a,b,c,d,e) { const numbers = [a,b,c,d,e]; numbers.forEach(number => console.log(number)); }, } </script>
では、呼び出す側でrestSample(1,2,3,4,5,6)のようにconsoleに出力したい数値に6を加えた場合、どうしたらいいでしょうか。
メソッドの定義側も修正する必要があり、ちょっと面倒ですし引数がさらに増えた場合また修正が必要になります。
// 引数にfを追加 restSample(a,b,c,d,e,f) { const numbers = [a,b,c,d,e,f]; numbers.forEach(number => console.log(number)); },
こういったときにRest演算子が役立ちます。Rest演算子では引数を可変長にすることができます。
<template> <div> <button @click="restSample(1,2,3,4,5,6)">test</button> </div> </template> <script> methods: { restSample(...numbers) { numbers.forEach(number => console.log(number)); }, } </script>
関数の引数に「…引数名」と書くことで引数を可変長の配列にように扱うことができます。これがRest演算子です。
restSampleでは引数を...numbersと書くことで、渡ってきた引数(1,2,3,4,5,6)を全て処理できています。
可変長の引数なので、引数がさらに増えても問題ありません。
<template> <div> <button @click="restSample(1,2,3,4,5,6,7,8,9,10)">test</button> </div> </template> <script> methods: { restSample(...numbers) { numbers.forEach(number => console.log(number)); }, } </script>
ES6から導入された分割代入という機能を使用することで、オブジェクトの値を簡潔に利用することができます。
オブジェクトの値を利用する場合、ES6以前は下記のようにsuzuki.heightとオブジェクト.キーで値を取得していたと思います。
test() { const suzuki = { height: 175, weight: 80 } const height = suzuki.height; const weight = suzuki.weight; console.log(height); console.log(weight); }
これを分割代入を使用することで、簡潔に記述することができます。
分割代入は
const height = suzuki.height;
と記述していたところを
const {height} = suzuki;
と利用したいオブジェクトのキーを中括弧でくくり、そこにオブジェクトを代入することで同じようにオブジェクトの値を取得できます。
{キー} の箇所は、オブジェクトのキーの名前と一致させる必要があります。
test() { const suzuki = { height: 175, weight: 80 } const {height} = suzuki; const {weight} = suzuki; console.log(height); console.log(weight); }
変数の名前を変えることもできます。
{キー名:変数名}= オブジェクト名;で任意の変数名を付けることが可能です。
test() { const suzuki = { height: 175, weight: 80 } // 変数名を変更 const {height: myHeight} = suzuki; const {weight: myWeight} = suzuki; console.log(myHeight); console.log(myWeight); }
メソッド内でインデントがあれば抽出できる可能性が高い。メソッドとして抽出して部品化を検討する。
if文を使って場合分けする場合は、elseを使わずに条件に合致した時点でreturnするガード節で記述する。
業務で扱うデータはintやStringで定義せずに、専用の型を用意して定義する。例えば電話番号ならTelephoneクラスを作成して変数と業務ロジックを中に作成する。 このような値を扱うために専用クラスを作るやり方を値オブジェクトと呼ぶ。
ドットを使って複数のメソッドを連ねた文は意図がわかりにくくなる。
ドットを使いたい場合、ドットの1つごとに説明用の変数に代入して別の文に分ける。
クラス名、メソッド名、変数名は省略して名前をつけない。例えばQuantity(数量)はqやqtyとつけずにそのままQuantityとつける。
長いメソッド、巨大なクラス、クラス数の多いパッケージは小さく分解する。
インスタンス変数とメソッドが密接に結びついたクラスは目的が単純で意図が明確になる。
インスタンス変数が増えるとクラスが複数の目的に使われ始め、コードが色々な理由で追加され巨大なクラスとなってしまう。
配列やコレクションを扱うコードは複雑になりやすい。配列やコレクションを操作するロジックを値オブジェクトと同じように専用の小さなクラスにまとめて整理することで、プログラムがわかりやすくなり変更が容易となる。
例えば顧客情報を複数持つ顧客一覧クラスCustomersの場合、インスタンス変数にList
このようにコレクション型のデータとロジックを特別扱いして、コレクションを1つだけ持つ専用クラスを作るやり方をコレクションオブジェクト、またはファーストクラスコレクションと呼ぶ。
手続き型の言語ではロジックは機能クラスに書き、データはデータクラスに書くというロジックとデータをクラスで分ける設計が普通だった。しかしgetterとsetterを持つデータクラスを利用することは様々な問題が発生する。
例えばgetterはそのまま値を返すだけなので、ロジックをデータクラスを利用する側に記述することになる。そしてデータクラスにアクセスできるクラスが複数あると、様々なクラスにロジックを書けてしまうので同じロジックが重複しやすい。そのため、データクラスは使わずにデータとロジックを1つのクラスにまとめた値オブジェクトを利用する。